Completed
Push — work-fleets ( 8591a1...0fb536 )
by SuperNova.WS
07:12
created

sn_module::mergeArraySpecial()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 3
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
ccs 0
cts 3
cp 0
crap 2
1
<?php
2
3
class sn_module {
4
  /**
5
   * @var sn_module[]
6
   */
7
  protected static $sn_module = array();
8
9
  public static $sn_module_list = array();
10
11
  public $manifest = array(
12
    'package'   => 'core',
13
    'name'      => 'sn_module',
14
    'version'   => '1c0',
15
    'copyright' => 'Project "SuperNova.WS" #41a52.93# copyright © 2009-2014 Gorlum',
16
17
    'require'       => array(),
18
    'root_relative' => '',
19
20
    'installed' => true,
21
    'active'    => true,
22
23
    // 'constants' array - contents of this array would be instaled into engine. 'UNIT_STRUCTURE_NEW' => 999999,
24
    'constants' => array(),
25
26
    'vars'      => array(), // Just a placeholder. vars assigned via special method __assign_vars(). Need 'cause of new constants that can be defined within module. See below
27
28
    /**
29
     * 'functions' array - this functions would be installed as hooks
30
     * Key: overwritable function name to replace
31
     * Value: which method to use. Format: [*][<object_name>][.]<method>
32
     * '*' means that new function would replace old one
33
     * If object_name is ommited but "." is present - hook linked to global function
34
     * If only "method" present - overwritable linked to appropriate method of current object
35
     * Examples:
36
     * 'test_object.test_method' - will
37
     * Function/Method should be accessible on module init
38
     * //      'test_object_test_method' => 'test_object.test_method',
39
     * //      'test_function' => '.my_test_function',
40
     * //      'this_object_test_method' => 'test_method',
41
     */
42
    'functions' => array(),
43
44
    // 'menu' array - this menu items would be merged into main game menu
45
    // Array element almost identical to $sn_menu with additional param 'LOCATION'.
46
    // 'LOCATION' => '-news', // Special atrtribute for modules
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
47
    // [-|+][<menu_item_id>]
0 ignored issues
show
Unused Code Comprehensibility introduced by
46% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
48
    // <menu_item_id> identifies menu item aginst new menu item would be placed. When ommited new item placed against whole menu
49
    // -/+ indicates that new item should be placed before/after identified menu item (or whole menu). If ommited and menu item exists - new item will replace previous one
50
    // Empty or non-existent LOCATION equivalent to '+' - place item at end of menu
51
    // Non-existent menu_item_id treated as ommited
52
    'menu'      => array(),
53
54
    // 'page' array - defines pages which will handle this module and appropriate handlers
55
    'page'      => array(),
56
  );
57
58
  protected $config = array();
59
60
  protected $module_full_class_path = __FILE__;
61
62
  /**
63
   * Динамическое назначение переменных
64
   *
65
   * Актуально, когда записываемые данные зависят от статуса игры
66
   * Например - назначаются константы внутри модуля
67
   *
68
   * @return array
69
   */
70
  public function __assign_vars() {
71
    return array();
72
  }
73
74
  public function loadModuleRootConfig() {
75
    require SN_ROOT_PHYSICAL . 'config.php';
76
77
    $module_config_array = get_class($this) . '_config';
78
    if(!empty($$module_config_array) && is_array($$module_config_array)) {
79
      $this->config = $$module_config_array;
80
81
      return true;
82
    }
83
84
    return false;
85
  }
86
87
  public function __construct($filename = __FILE__) {
88
    // Getting module PHP class name
89
    $class_module_name = get_class($this);
90
91
    // Getting module root relative to SN
92
    $this->manifest['root_relative'] = str_replace(array(SN_ROOT_PHYSICAL, basename($filename)), '', str_replace('\\', '/', $filename));
93
94
    // TODO: Load configuration from DB. Manifest setting
95
    // Trying to load configuration from file
96
    if(!$config_exists = $this->loadModuleRootConfig()) {
97
      // Конфигурация может лежать в config_path в манифеста или в корне модуля
98
      if(isset($this->manifest['config_path']) && file_exists($config_filename = $this->manifest['config_path'] . '/config.php')) {
99
        $config_exists = true;
100
      } elseif(file_exists($config_filename = dirname($filename) . '/config.php')) {
101
        $config_exists = true;
102
      }
103
104
      if($config_exists) {
105
        include($config_filename);
106
        $module_config_array = $class_module_name . '_config';
107
        $this->config = $$module_config_array;
108
      }
109
    }
110
111
    // Registering module
112
    self::$sn_module[$class_module_name] = $this;
113
  }
114
115
116
  public function initialize() {
117
    global $sn_menu_extra, $sn_menu_admin_extra;
118
119
    // Checking module status - is it installed and active
120
    $this->check_status();
121
    if(!$this->manifest['active']) {
122
      return;
123
    }
124
125
    $this->setSystemConstants();
126
    $this->setSystemVariables();
127
    $this->addSystemHandlers();
128
    $this->mergeI18N();
129
130
    // Patching game menu - if any
131
    isset($this->manifest['menu']) ? $this->mergeMenu($sn_menu_extra, $this->manifest['menu']) : false;
132
    isset($this->manifest['menu_admin']) ? $this->mergeMenu($sn_menu_admin_extra, $this->manifest['menu_admin']) : false;
133
134
    $this->mergeJavascript();
135
    $this->mergeCss();
136
    $this->mergeNavbarButton();
137
  }
138
139
  protected function setSystemConstants() {
140
    // Setting constants - if any
141
    if(empty($this->manifest['constants']) || !is_array($this->manifest['constants'])) {
142
      return;
143
    }
144
145
    foreach($this->manifest['constants'] as $constant_name => $constant_value) {
146
      !defined($constant_name) ? define($constant_name, $constant_value) : false;
147
    }
148
  }
149
150
  protected function setSystemVariables() {
151
    // Adding vars - if any
152
    // Due to possible introduce of new constants in previous step vars is assigned via special method to honor new constants
153
    // Assignation can work with simple variables and with multidimensional arrays - for ex. 'sn_data[groups][test]'
154
    // New values from module variables will overwrite previous values (for root variables) and array elements with corresponding indexes (for arrays)
155
    // Constants as array indexes are honored - it's make valid such declarations as 'sn_data[ques][QUE_STRUCTURES]'
156
    $this->manifest['vars'] = $this->__assign_vars();
157
    if(empty($this->manifest['vars']) || !is_array($this->manifest['vars'])) {
158
      return;
159
    }
160
161
    $vars_assigned = array();
162
    foreach($this->manifest['vars'] as $var_name => $var_value) {
163
      $sub_vars = explode('[', str_replace(']', '', $var_name));
164
      $var_name = $sub_vars[0];
165
166
      if(!isset($vars_assigned[$var_name])) {
167
        $vars_assigned[$var_name] = true;
168
        global $$var_name;
169
      }
170
171
      $pointer = &$$var_name;
172
      if(($n = count($sub_vars)) > 1) {
173
        for($i = 1; $i < $n; $i++) {
174
          if(defined($sub_vars[$i])) {
175
            $sub_vars[$i] = constant($sub_vars[$i]);
176
          }
177
178
          if(!isset($pointer[$sub_vars[$i]]) && $i != $n) {
179
            $pointer[$sub_vars[$i]] = array();
180
          }
181
          $pointer = &$pointer[$sub_vars[$i]];
182
        }
183
      }
184
185
      if(!isset($pointer) || !is_array($pointer)) {
186
        $pointer = $var_value;
187
      } elseif(is_array($$var_name)) {
188
        $pointer = array_merge_recursive_numeric($pointer, $var_value);
189
      }
190
    }
191
  }
192
193
  protected function mergeMenu(&$sn_menu_extra, &$menu_patch) {
194
    if(!is_array($menu_patch)) {
195
      return;
196
    }
197
198
    foreach($menu_patch as $menu_item_name => $menu_item_data) {
199
      $sn_menu_extra[$menu_item_name] = $menu_item_data;
200
    }
201
  }
202
203
  protected function addSystemHandlers() {
204
    // Overriding function if any
205
    sn_sys_handler_add(classSupernova::$functions, $this->manifest['functions'], $this);
206
207
    foreach(classSupernova::$sn_mvc as $handler_type => &$handler_data) {
208
      sn_sys_handler_add($handler_data, $this->manifest['mvc'][$handler_type], $this, $handler_type);
209
    }
210
  }
211
212
  protected function mergeNavbarButton() {
213
    if(empty($this->manifest['navbar_prefix_button']) || !is_array($this->manifest['navbar_prefix_button'])) {
214
      return;
215
    }
216
217
    foreach($this->manifest['navbar_prefix_button'] as $button_image => $button_url_relative) {
218
      classSupernova::$sn_mvc['navbar_prefix_button'][$button_image] = $button_url_relative;
219
    }
220
  }
221
222
  protected function mergeI18N() {
223
    $arrayName = 'i18n';
224
    if(empty($this->manifest[$arrayName]) || !is_array($this->manifest[$arrayName])) {
225
      return;
226
    }
227
228
    foreach($this->manifest[$arrayName] as $pageName => &$contentList) {
229
      foreach($contentList as &$i18n_file_data) {
230
        if(is_array($i18n_file_data) && !$i18n_file_data['path']) {
231
          $i18n_file_data['path'] = $this->manifest['root_relative'];
232
        }
233
      }
234
      if(!isset(classSupernova::$sn_mvc[$arrayName][$pageName])) {
235
        classSupernova::$sn_mvc[$arrayName][$pageName] = array();
236
      }
237
      classSupernova::$sn_mvc[$arrayName][$pageName] += $contentList;
238
    }
239
  }
240
241
  /**
242
   * @param string     $arrayName - name of manifest fields to get data from
243
   */
244
  protected function mergeArraySpecial($arrayName) {
245
    $this->mergeArrayParam($this->manifest[$arrayName], classSupernova::$sn_mvc[$arrayName]);
246
  }
247
248
  /**
249
   * @param array $arrayFrom
250
   * @param array $arrayMergeTo
251
   */
252
  protected function mergeArrayParam(&$arrayFrom, &$arrayMergeTo) {
253
    if (!is_array($arrayFrom) || empty($arrayFrom)) {
254
      return;
255
    }
256
257
    foreach ($arrayFrom as $pageName => &$contentList) {
258
      !isset($arrayMergeTo[$pageName]) ? $arrayMergeTo[$pageName] = array() : false;
259
      foreach ($contentList as $contentName => &$content) {
260
        $arrayMergeTo[$pageName][$contentName] = $content;
261
      }
262
    }
263
  }
264
265
  protected function mergeCss() { $this->mergeArrayParam($this->manifest['css'], classSupernova::$css); }
266
267
  protected function mergeJavascript() { $this->mergeArraySpecial('javascript'); }
268
269
  public function check_status() { }
270
271
  public static function orderModules() {
272
// load_order:
273
//  100000 - default load order
274
//  999999 - core_ship_constructor
275
//  2000000000 - that requires that all possible modules loaded already
276
//  2000100000 - game_skirmish
277
278
// Генерируем список требуемых модулей
279
    $load_order = array();
280
    $sn_req = array();
281
282
    foreach (sn_module::$sn_module as $loaded_module_name => $module_data) {
283
      $load_order[$loaded_module_name] = !empty($module_data->manifest['load_order']) ? $module_data->manifest['load_order'] : 100000;
284
      if (!empty($module_data->manifest['require'])) {
285
        foreach ($module_data->manifest['require'] as $require_name) {
286
          $sn_req[$loaded_module_name][$require_name] = 0;
287
        }
288
      }
289
    }
290
291
// pdump($load_order, '$load_order');
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
292
293
// Создаем последовательность инициализации модулей
294
// По нормальным делам надо сначала читать их конфиги - вдруг какой-то модуль отключен?
295
    do {
296
      $prev_order = $load_order;
297
298
      foreach ($sn_req as $loaded_module_name => &$req_data) {
299
        $level = 1;
300
        foreach ($req_data as $req_name => &$req_level) {
301
          if ($load_order[$req_name] == -1 || !isset($load_order[$req_name])) {
302
            $level = $req_level = -1;
303
            break;
304
          } else {
305
            $level += $load_order[$req_name];
306
          }
307
          $req_level = $load_order[$req_name];
308
        }
309
        if ($level > $load_order[$loaded_module_name] || $level == -1) {
310
          $load_order[$loaded_module_name] = $level;
311
        }
312
      }
313
    } while($prev_order != $load_order);
314
315
    asort($load_order);
316
317
    unset($sn_req);
318
319
// Инициализируем модули
320
// По нормальным делам это должна быть загрузка модулей и лишь затем инициализация - что бы минимизировать размер процесса в памяти
321
    foreach ($load_order as $loaded_module_name => $load_order_order) {
322
      if ($load_order_order >= 0) {
323
        sn_module::$sn_module[$loaded_module_name]->check_status();
324
        if (!sn_module::$sn_module[$loaded_module_name]->manifest['active']) {
325
          unset(sn_module::$sn_module[$loaded_module_name]);
326
          continue;
327
        }
328
329
        sn_module::$sn_module[$loaded_module_name]->initialize();
330
        sn_module::$sn_module_list[sn_module::$sn_module[$loaded_module_name]->manifest['package']][$loaded_module_name] = &sn_module::$sn_module[$loaded_module_name];
331
      } else {
332
        unset(sn_module::$sn_module[$loaded_module_name]);
333
      }
334
    }
335
336
// Скрипач не нужон
337
    unset($load_order);
338
  }
339
340
  /**
341
   * @param string $moduleName
342
   *
343
   * @return bool
344
   */
345
  public static function isModuleActive($moduleName) {
346
    return
347
      !empty(sn_module::$sn_module[$moduleName])
348
      &&
349
      sn_module::$sn_module[$moduleName] instanceof sn_module
350
      &&
351
      sn_module::$sn_module[$moduleName]->manifest['active'];
352
  }
353
354
  /**
355
   * @param string $moduleName
356
   *
357
   * @return sn_module
358
   */
359
  public static function getModule($moduleName) {
360
    return sn_module::$sn_module[$moduleName];
361
  }
362
363
}
364