sn_module::initialize()   F
last analyzed

Complexity

Conditions 53
Paths > 20000

Size

Total Lines 131
Code Lines 72

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2862

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 53
eloc 72
nc 23041
nop 0
dl 0
loc 131
rs 0
c 1
b 0
f 0
ccs 0
cts 104
cp 0
crap 2862

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Modules;
4
5
use Common\Hooker\Pimp;
6
use Core\Autoloader;
7
use Exception;
8
use SN;
9
use SnTemplate;
10
use template;
11
12
class sn_module {
13
  // Manifest params
14
  const M_REQUIRE = 'require';
15
  const M_ROOT_RELATIVE = 'root_relative';
16
  const M_LOAD_ORDER = 'load_order';
17
18
  const MANIFEST_CSS = 'css';
19
20
  /**
21
   * SN version in which module was committed. Can be treated as version in which module guaranteed to work
22
   * @var string $versionCommitted
23
   */
24
  public $versionCommitted = '#46a161#';
25
  /**
26
   * Is module currently active?
27
   *
28
   * @var bool $active
29
   */
30
  protected $active = true;
31
  /**
32
   * Is all module DB artifacts presents?
33
   *
34
   * Check for module's tables, settings etc
35
   *
36
   * @var bool $installed
37
   */
38
  protected $installed = true;
39
40
  public $manifest = [
41
    'package'   => 'core',
42
    'name'      => 'Modules\sn_module',
43
    'version'   => '1c0',
44
    'copyright' => 'Project "SuperNova.WS" #46a161# copyright © 2009-2018 Gorlum',
45
46
    self::M_LOAD_ORDER => MODULE_LOAD_ORDER_DEFAULT,
47
48
    self::M_REQUIRE       => [],
49
    self::M_ROOT_RELATIVE => '',
50
51
    // 'constants' array - contents of this array would be defined in SN
52
    'constants'           => [
53
//      'UNIT_STRUCTURE_NEW' => 999999,
54
    ],
55
56
    'vars'      => [], // Just a placeholder. vars assigned via special method __assign_vars(). Need 'cause of new constants that can be defined within module. See below
57
58
    // 'functions' array - this functions would be installed as hooks
59
    // Key: overwritable function name to replace
60
    // Value: which method to use. Format: [*][<object_name>][.]<method>
61
    // '*' means that new function would replace old one
62
    // If object_name is ommited but "." is present - hook linked to global function
63
    // If only "method" present - overwritable linked to appropriate method of current object
64
    // Function/Method should be accessible on module init
65
    'functions' => [
66
//      'test_object_test_method' => 'test_object.test_method',
67
//      'test_function' => '.my_test_function',
68
//      'this_object_test_method' => 'test_method',
69
    ],
70
71
    // 'menu' array - this menu items would be merged into main game menu
72
    // Array element almost identical to $sn_menu with additional param 'LOCATION'.
73
    // 'LOCATION' => '-news', // Special atrtribute for modules
74
    // [-|+][<menu_item_id>]
75
    // <menu_item_id> identifies menu item aginst new menu item would be placed. When ommited new item placed against whole menu
76
    // -/+ 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
77
    // Empty or non-existent LOCATION equivalent to '+' - place item at end of menu
78
    // Non-existent menu_item_id treated as ommited
79
    'menu'      => [],
80
81
    // 'page' array - defines pages which will handle this module and appropriate handlers
82
    'page'      => [],
83
84
    /**
85
     * 'mvc' subarray
86
     * [
87
     *    FIELD_MODEL =>
88
     *    FIELD_VIEW =>
89
     *    MVC_OPTIONS =>
90
     * ]
91
     */
92
    'mvc'       => [],
93
  ];
94
95
  /**
96
   * New way to add functions instead of manifest['functions']
97
   *
98
   * [
99
   *   (string)$functionName => [
100
   *     (callable)$callable,
101
   *     (string)'methodName',                             // Local method name aka $this->methodName
102
   *     (callable array)[$this|objectName, 'methodName'], // Callable array
103
   *   ],
104
   * ]
105
   *
106
   * @var array $functions
107
   */
108
  protected $functions = [];
109
110
  protected $hooks = [];
111
112
  protected $config = array();
113
114
  protected $module_full_class_path = __FILE__;
115
116
  protected $filename = '';
117
118
  /**
119
   * @param string   $functionName
120
   * @param callable $callable
121
   */
122
  public function addFunctionHook($functionName, $callable) {
123
    $this->functions[$functionName][] = $callable;
124
  }
125
126
  /**
127
   * Динамическое назначение переменных
128
   *
129
   * Актуально, когда записываемые данные зависят от статуса игры
130
   * Например - назначаются константы внутри модуля
131
   *
132
   * @return array
133
   */
134
  protected function __assign_vars() {
135
    return array(/*
136
      'sn_data' => array(
137
        UNIT_STRUCTURE_NEW => array( // Will honor new constants
138
          'name' => 'robot_factory',
139
          'type' => UNIT_STRUCTURE,
140
          'location' => LOC_PLANET,
141
          'cost' => array(
142
            RES_METAL     => 400,
143
            RES_CRYSTAL   => 120,
144
            RES_DEUTERIUM => 200,
145
            RES_ENERGY    => 0,
146
            'factor' => 2,
147
          ),
148
          'metal' => 400,
149
          'crystal' => 120,
150
          'deuterium' => 200,
151
          'energy' => 0,
152
          'factor' => 2,
153
        ),
154
      ),
155
*/
156
    );
157
  }
158
159
  /**
160
   * sn_module constructor.
161
   *
162
   * @param string $filename
163
   *
164
   * @throws Exception
165
   */
166
  public function __construct($filename = __FILE__) {
167
    $this->filename = $filename;
168
169
    // Getting module PHP class name
170
    $class_module_name = get_called_class();
171
172
    // Validating source settings. Some fields are mandatory in each manifest
173
    // Should be removed when manifest would be parsed to separate fields
174
    foreach (['name', 'package', 'version'] as $mandatoryManifest) {
175
      if (!array_key_exists($mandatoryManifest, $this->manifest)) {
176
        throw new Exception('{ There is no mandatory field "' . $mandatoryManifest . '" in manifest of module } "' . $class_module_name . '"');
177
      }
178
    }
179
180
    // Getting module root relative to SN
181
    $this->manifest[static::M_ROOT_RELATIVE] = str_replace(
182
      [SN_ROOT_PHYSICAL, basename($this->filename)],
183
      '',
184
      str_replace('\\', '/', $this->filename)
185
    );
186
187
    // TODO: Load configuration from DB. Manifest setting
188
    // Trying to load configuration from file
189
    $config_exists = false;
190
    // Конфигурация может лежать в config_path в манифеста или в корне модуля
191
    if (isset($this->manifest['config_path']) && file_exists($config_filename = $this->manifest['config_path'] . '/' . SN_MODULE_CONFIG_NAME)) {
192
      $config_exists = true;
193
    } elseif (file_exists($config_filename = dirname($filename) . '/' . SN_MODULE_CONFIG_NAME)) {
194
      $config_exists = true;
195
    }
196
197
    if ($config_exists) {
198
      /** @noinspection PhpIncludeInspection */
199
      include($config_filename);
200
      $module_config_array = $class_module_name . '_config';
201
      $this->config        = $$module_config_array;
202
    }
203
204
    // Registering classes with autoloader
205
    Autoloader::register($this->getRootRelative() . 'classes/');
206
207
    // TODO - currently not possible because each module is not a service
208
    // When it's done - remove double registration from loadModulesFromDirectory()
209
    // Registering module in manager
210
//    SN::$gc->modules->registerModule($class_module_name, $this);
211
  }
212
213
  protected function __patch_menu(&$sn_menu_extra, &$menu_patch, $admin = false) {
214
    if (isset($menu_patch) && is_array($menu_patch) && !empty($menu_patch)) {
215
      foreach ($menu_patch as $menu_item_name => $menu_item_data) {
216
        $sn_menu_extra[$menu_item_name] = $menu_item_data;
217
      }
218
    }
219
  }
220
221
222
  /**
223
   *
224
   */
225
  public function initialize() {
226
    // Checking module status - is it installed and active
227
    $this->check_status();
228
    if (!$this->isActive()) {
229
      return;
230
    }
231
232
    // Setting constants - if any
233
    if (isset($this->manifest['constants']) && is_array($this->manifest['constants']) && !empty($this->manifest['constants'])) {
234
      foreach ($this->manifest['constants'] as $constant_name => $constant_value) {
235
        defined($constant_name) or define($constant_name, $constant_value);
236
      }
237
    }
238
239
    // Adding vars - if any
240
    // Due to possible introduce of new constants in previous step vars is assigned via special method to honor new constants
241
    // Assignation can work with simple variables and with multidimensional arrays - for ex. 'sn_data[groups][test]'
242
    // New values from module variables will overwrite previous values (for root variables) and array elements with corresponding indexes (for arrays)
243
    // Constants as array indexes are honored - it's make valid such declarations as 'sn_data[ques][QUE_STRUCTURES]'
244
    $this->manifest['vars'] = $this->__assign_vars();
245
    if (!empty($this->manifest['vars'])) {
246
      $vars_assigned = array();
247
      foreach ($this->manifest['vars'] as $var_name => $var_value) {
248
        $sub_vars = explode('[', str_replace(']', '', $var_name));
249
        $var_name = $sub_vars[0];
250
251
        if (!isset($vars_assigned[$var_name])) {
252
          $vars_assigned[$var_name] = true;
253
          global $$var_name;
254
        }
255
256
        $pointer = &$$var_name;
257
        if (($n = count($sub_vars)) > 1) {
258
          for ($i = 1; $i < $n; $i++) {
259
            if (defined($sub_vars[$i])) {
260
              $sub_vars[$i] = constant($sub_vars[$i]);
261
            }
262
263
            if (!isset($pointer[$sub_vars[$i]]) && $i != $n) {
264
              $pointer[$sub_vars[$i]] = array();
265
            }
266
            $pointer = &$pointer[$sub_vars[$i]];
267
          }
268
        }
269
270
        if (!isset($pointer) || !is_array($pointer)) {
271
          $pointer = $var_value;
272
        } elseif (is_array($$var_name)) {
273
          $pointer = array_merge_recursive_numeric($pointer, $var_value);
274
        }
275
      }
276
    }
277
278
    // Overriding function if any
279
    global $functions;
280
    sn_sys_handler_add($functions, $this->manifest['functions'], $this);
281
282
    foreach ($this->functions as $functionName => $callableList) {
283
      !is_array($callableList) ? $callableList = [$callableList] : false;
284
      foreach ($callableList as $callable) {
285
        sys_handler_add_one($functions, $functionName, $callable, static::class, '');
286
      }
287
    }
288
289
    $this->registerHooks();
290
291
    // Patching game menu - if any
292
    global $sn_menu_extra, $sn_menu_admin_extra;
293
    isset($this->manifest['menu']) and $this->__patch_menu($sn_menu_extra, $this->manifest['menu']);
294
    isset($this->manifest['menu_admin']) and $this->__patch_menu($sn_menu_admin_extra, $this->manifest['menu_admin'], true);
295
296
    global $sn_mvc;
297
    foreach ($sn_mvc as $handler_type => &$handler_data) {
298
      if ($handler_type == MVC_OPTIONS) {
299
        continue;
300
      }
301
      sn_sys_handler_add($handler_data, $this->manifest['mvc'][$handler_type], $this, $handler_type);
302
    }
303
304
    if (!empty($this->manifest['mvc'][MVC_OPTIONS])) {
305
      foreach ($this->manifest['mvc'][MVC_OPTIONS] as $pageName => $pageOptions) {
306
        if (empty($pageOptions)) {
307
          continue;
308
        }
309
310
        !is_array($sn_mvc['pages'][$pageName][MVC_OPTIONS]) ? $sn_mvc['pages'][$pageName][MVC_OPTIONS] = [] : false;
311
        $sn_mvc['pages'][$pageName][MVC_OPTIONS] = array_merge($sn_mvc['pages'][$pageName][MVC_OPTIONS], $pageOptions);
312
      }
313
    }
314
315
    if (isset($this->manifest['i18n']) && is_array($this->manifest['i18n']) && !empty($this->manifest['i18n'])) {
316
      foreach ($this->manifest['i18n'] as $i18n_page_name => &$i18n_file_list) {
317
        foreach ($i18n_file_list as &$i18n_file_data) {
318
          if (is_array($i18n_file_data) && !$i18n_file_data['path']) {
319
            $i18n_file_data['path'] = $this->getRootRelative();
320
          }
321
        }
322
        if (!isset($sn_mvc['i18n'][$i18n_page_name])) {
323
          $sn_mvc['i18n'][$i18n_page_name] = array();
324
        }
325
        $sn_mvc['i18n'][$i18n_page_name] += $i18n_file_list;
326
      }
327
    }
328
329
    if (!empty($this->manifest['javascript']) && is_array($this->manifest['javascript'])) {
330
      foreach ($this->manifest['javascript'] as $javascript_page_name => &$javascript_list) {
331
        !isset($sn_mvc['javascript'][$javascript_page_name]) ? $sn_mvc['javascript'][$javascript_page_name] = array() : false;
332
        foreach ($javascript_list as $script_name => &$script_content) {
333
          $sn_mvc['javascript'][$javascript_page_name][$script_name] = $script_content;
334
        }
335
      }
336
    }
337
338
    if (!empty($this->manifest['css']) && is_array($this->manifest['css'])) {
339
      foreach ($this->manifest['css'] as $javascript_page_name => &$javascript_list) {
340
        !isset($sn_mvc['css'][$javascript_page_name]) ? $sn_mvc['css'][$javascript_page_name] = array() : false;
341
        foreach ($javascript_list as $script_name => &$script_content) {
342
          $sn_mvc['css'][$javascript_page_name][$script_name] = $script_content;
343
        }
344
      }
345
    }
346
347
    if (!empty($this->manifest['navbar_prefix_button']) && is_array($this->manifest['navbar_prefix_button'])) {
348
      foreach ($this->manifest['navbar_prefix_button'] as $button_image => $button_url_relative) {
349
        $sn_mvc['navbar_prefix_button'][$button_image] = $button_url_relative;
350
      }
351
    }
352
353
    if (!empty($this->manifest['navbar_main_button']) && is_array($this->manifest['navbar_main_button'])) {
354
      foreach ($this->manifest['navbar_main_button'] as $button_image => $button_url_relative) {
355
        $sn_mvc['navbar_main_button'][$button_image] = $button_url_relative;
356
      }
357
    }
358
  }
359
360
  public function check_status() {
361
  }
362
363
  /**
364
   * Checks if module is active
365
   *
366
   * @return bool
367
   */
368
  public function isActive() {
369
    return !empty($this->active) && $this->isInstalled();
370
  }
371
372
  /**
373
   * Checks if module is installed
374
   *
375
   * @return bool
376
   */
377
  public function isInstalled() {
378
    return !empty($this->installed);
379
  }
380
381
  /**
382
   * Register pages in $manifest['mvc']['pages'] for further use
383
   *
384
   * @param string[] $pages - array of records ['pageName' => 'pageFile']. 'pageFile' is currently unused
385
   *
386
   * @deprecated
387
   */
388
  protected function __mvcRegisterPagesOld($pages) {
389
    !is_array($this->manifest['mvc']['pages']) ? $this->manifest['mvc']['pages'] = [] : false;
390
    if (is_array($pages) && !empty($pages)) {
391
      $this->manifest['mvc']['pages'] = array_merge($this->manifest['mvc']['pages'], $pages);
392
    }
393
  }
394
395
  protected function registerHooks() {
396
    foreach ($this->hooks as $hookName => $hookRecord) {
397
      // Priority can be first element of hook array
398
      $priority = Pimp::ORDER_AS_IS;
399
      if (is_array($hookRecord) && count($hookRecord) > 1 && is_numeric(reset($hookRecord))) {
400
        $priority = intval(reset($hookRecord));
401
        array_shift($hookRecord);
402
      }
403
404
      // There is 2 elements in callable array
405
      if (is_array($hookRecord) && 2 == count($hookRecord)) {
406
        // Checking - if first should be replaced with $this
407
        if (THIS_STRING === reset($hookRecord)) {
408
          $hookRecord = [$this, end($hookRecord)];
409
        }
410
      }
411
412
      SN::$gc->pimp->register($hookName, $hookRecord, $priority);
413
    }
414
  }
415
416
  public function getLoadOrder() {
417
    return !empty($this->manifest[self::M_LOAD_ORDER]) ? $this->manifest[self::M_LOAD_ORDER] : MODULE_LOAD_ORDER_DEFAULT;
418
  }
419
420
  public function getRootRelative() {
421
    if (empty($this->manifest[static::M_ROOT_RELATIVE])) {
422
      $this->manifest[static::M_ROOT_RELATIVE] = str_replace([SN_ROOT_PHYSICAL, basename($this->filename)], '', str_replace('\\', '/', $this->filename));
423
    }
424
425
    return $this->manifest[static::M_ROOT_RELATIVE];
426
  }
427
428
  protected function getTemplateRootRelative() {
429
    return $this->getRootRelative() . SnTemplate::SN_TEMPLATES_PARTIAL_PATH;
430
  }
431
432
  /**
433
   *
434
   * Should stay public due using in Festivals (?)
435
   *
436
   * @param string        $templateName
437
   * @param template|null $template
438
   *
439
   * @return template
440
   */
441
  public function addModuleTemplate($templateName, $template) {
442
    return SnTemplate::gettemplate(
443
      $templateName,
444
      $template,
445
      SN_ROOT_PHYSICAL . $this->getTemplateRootRelative(),
446
      is_object($template) ? $template->root : SnTemplate::getCurrentTemplate()->getPathFull()
447
    );
448
  }
449
450
  /**
451
   * @param string $jsName
452
   *
453
   * @return array
454
   */
455
  protected function addModuleJavascript($jsName) {
456
    global $template_result, $sn_mvc;
457
458
    if (empty($sn_mvc['javascript_filenames'])) {
459
      $sn_mvc['javascript_filenames'] = [];
460
    }
461
    $sn_mvc['javascript_filenames'][] = $this->getRootRelative() . $jsName;
462
463
    return $template_result;
464
  }
465
466
  /**
467
   * Get module version
468
   *
469
   * @return string
470
   */
471
  public function getVersion() {
472
    if (!empty($this->versionCommitted)) {
473
      $version = $this->versionCommitted;
474
    } else {
475
      $version = $this->manifest['version'];
476
    }
477
478
    return trim($version, '#');
479
  }
480
481
  /**
482
   * Get module full name as registered in module manager
483
   *
484
   * @return string
485
   */
486
  public function getFullName() {
487
    return get_called_class();
488
  }
489
490
}
491