Completed
Push — trunk ( 0f5c9b...1c4b6b )
by SuperNova.WS
05:17 queued 29s
created

Manager::loadModulesFromDirectory()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
cc 7
eloc 9
nc 5
nop 2
dl 0
loc 16
ccs 0
cts 11
cp 0
crap 56
rs 8.2222
c 0
b 0
f 0
1
<?php
2
/**
3
 * Created by Gorlum 19.03.2018 19:56
4
 */
5
6
namespace Modules;
7
8
use \sn_module;
9
use Common\GlobalContainer;
10
11
12
/**
13
 * Class Manager
14
 *
15
 * Modules Manager
16
 * Replacement for removed $sn_module and $sn_module_list global variables
17
 *
18
 * @package Modules
19
 */
20
class Manager {
21
  /**
22
   * @var GlobalContainer $gc
23
   */
24
  protected $gc;
25
26
  /**
27
   * Is modules already loaded?
28
   *
29
   * @var bool $modulesAreLoaded
30
   */
31
  protected $modulesAreLoaded = false;
32
33
  /**
34
   * Plain list of available modules
35
   *
36
   * @var sn_module[] $modules - [(string)$moduleName => (sn_module)$module]
37
   */
38
  protected $modules = [];
39
40
  /**
41
   * Modules arranged per package
42
   *
43
   * @var sn_module[][] $packages - [[(string)$package] => [(string)$moduleName => (sn_module)$module]]
44
   */
45
  protected $packages = [];
46
47
48
  /**
49
   * Manager constructor.
50
   *
51
   * @param GlobalContainer $gc
52
   */
53
  public function __construct($gc) {
54
    $this->gc = $gc;
55
56
    $this->loadModules(SN_ROOT_MODULES);
57
  }
58
59
60
  /**
61
   * @param string $dir_name
62
   */
63
  public function loadModules($dir_name = SN_ROOT_MODULES) {
64
    if ($this->modulesAreLoaded) {
65
      return;
66
    }
67
68
    if (file_exists($dir_name) && is_dir($dir_name)) {
69
      $this->loadModulesFromDirectory($dir_name, PHP_EX);
70
    }
71
72
    $this->modulesAreLoaded = true;
73
  }
74
75
  /**
76
   *
77
   */
78
  public function initModules() {
79
    $loadOrder = $this->getLoadOrder();
80
81
    // Инициализируем модули
82
    // По нормальным делам это должна быть загрузка модулей и лишь затем инициализация - что бы минимизировать размер процесса в памяти
83
    foreach ($loadOrder as $moduleName => $place) {
84
      $module = $this->modules[$moduleName];
85
86
      if ($place >= 0) {
87
        $module->check_status();
88
        if (!$module->isActive()) {
89
          unset($this->modules[$moduleName]);
90
          continue;
91
        }
92
93
        $module->initialize();
94
      } else {
95
        unset($module);
96
      }
97
    }
98
  }
99
100
  /**
101
   * @param $dir_name
102
   * @param $load_extension
103
   */
104
  protected function loadModulesFromDirectory($dir_name, $load_extension) {
105
    $dir = opendir($dir_name);
106
    while (($file = readdir($dir)) !== false) {
0 ignored issues
show
Bug introduced by
It seems like $dir can also be of type false; however, parameter $dir_handle of readdir() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

106
    while (($file = readdir(/** @scrutinizer ignore-type */ $dir)) !== false) {
Loading history...
107
      if ($file == '..' || $file == '.') {
108
        continue;
109
      }
110
111
      $full_filename = $dir_name . $file;
112
      if (is_dir($full_filename) && file_exists($full_filename = "{$full_filename}/{$file}.{$load_extension}")) {
113
        require_once($full_filename);
114
115
        // Registering module
116
        if (class_exists($file)) {
117
          // TODO Module SHOULD register himself!
118
//          new $file($full_filename)
119
          $this->registerModule($file, new $file($full_filename));
120
        }
121
      }
122
    }
123
  }
124
125
  /**
126
   * Get module load order counting requirements and each module load order
127
   *
128
   * @return int[] - [(string)$moduleName => (int)$loadOrder]
129
   */
130
  protected function getLoadOrder() {
131
    // Генерируем список требуемых модулей
132
    $loadOrder = [];
133
    $sn_req = [];
134
135
    foreach ($this->modules as $loaded_module_name => $module) {
136
      $loadOrder[$loaded_module_name] = $module->getLoadOrder();
137
      if (!empty($module->manifest[sn_module::M_REQUIRE])) {
138
        foreach ($module->manifest[sn_module::M_REQUIRE] as $require_name) {
139
          $sn_req[$loaded_module_name][$require_name] = 0;
140
        }
141
      }
142
    }
143
144
    // Создаем последовательность инициализации модулей
145
    // По нормальным делам надо сначала читать их конфиги - вдруг какой-то модуль отключен?
146
    do {
147
      $prev_order = $loadOrder;
148
149
      foreach ($sn_req as $loaded_module_name => &$req_data) {
150
        $level = 1;
151
        foreach ($req_data as $req_name => &$req_level) {
152
          if ($loadOrder[$req_name] == -1 || !isset($loadOrder[$req_name])) {
153
            $level = $req_level = -1;
154
            break;
155
          } else {
156
            $level += $loadOrder[$req_name];
157
          }
158
          $req_level = $loadOrder[$req_name];
159
        }
160
        if ($level > $loadOrder[$loaded_module_name] || $level == -1) {
161
          $loadOrder[$loaded_module_name] = $level;
162
        }
163
      }
164
    } while ($prev_order != $loadOrder);
165
166
    asort($loadOrder);
167
168
    return $loadOrder;
169
  }
170
171
  /**
172
   * @param string|array $groups - Module group name or '' for any group
173
   *
174
   * @return int
175
   */
176
  public function getModulesActiveCount($groups = '') {
177
    return count($this->getModulesActive($groups));
178
  }
179
180
  /**
181
   * Getting list of active modules
182
   *
183
   * @param string|array $groups - Module group name or '' for any group
184
   *
185
   * @return sn_module[]
186
   */
187
  public function getModulesActive($groups = '') {
188
    // If no groups specified - iterating all groups
189
    if (empty($groups)) {
190
      $groups = array_keys($this->packages);
191
    }
192
193
    if (!is_array($groups)) {
194
      $groups = [$groups];
195
    }
196
197
    $activeModules = [];
198
    foreach ($groups as $groupName) {
199
      if (is_array($this->packages[$groupName]) && !empty($this->packages[$groupName])) {
200
        foreach ($this->packages[$groupName] as $moduleName => $module) {
201
          if ($module->isActive()) {
202
            $activeModules[$moduleName] = $module;
203
          }
204
        }
205
      }
206
    }
207
208
    return $activeModules;
209
  }
210
211
212
  /**
213
   * Get module by name
214
   *
215
   * @param string $moduleName
216
   *
217
   * @return null|sn_module
218
   */
219
  public function getModule($moduleName) {
220
    return !empty($this->modules[$moduleName]) ? $this->modules[$moduleName] : null;
221
  }
222
223
  /**
224
   * Register module for further use
225
   *
226
   * Basically modules does not exists anywhere except in Modules Manager
227
   *
228
   * @param string    $moduleName
229
   * @param sn_module $module
230
   */
231
  public function registerModule($moduleName, $module) {
232
    $this->modules[$moduleName] = $module;
233
    $this->packages[$module->manifest['package']][$moduleName] = &$this->modules[$moduleName];
234
  }
235
236
}
237