Passed
Push — master ( a4754c...e0c6ec )
by Nazar
05:32
created

modules::get_dependencies_for_module()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 4
nc 3
nop 1
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
ccs 0
cts 5
cp 0
crap 12
1
<?php
2
/**
3
 * @package    CleverStyle Framework
4
 * @subpackage System module
5
 * @category   modules
6
 * @author     Nazar Mokrynskyi <[email protected]>
7
 * @copyright  Copyright (c) 2015-2017, Nazar Mokrynskyi
8
 * @license    MIT License, see license.txt
9
 */
10
namespace cs\modules\System\api\Controller\admin;
11
use
12
	cs\Cache as System_cache,
13
	cs\Config,
14
	cs\Event,
15
	cs\ExitException,
16
	cs\Language,
17
	cs\Permission,
18
	cs\Session,
19
	cs\modules\System\Packages_dependencies,
20
	cs\modules\System\Packages_manipulation;
21
22
trait modules {
23
	/**
24
	 * @param \cs\Request $Request
25
	 *
26
	 * @return mixed
27
	 *
28
	 * @throws ExitException
29
	 */
30
	public static function admin_modules_get ($Request) {
31
		if ($Request->route_path(3)) {
32
			$route_path = $Request->route_path;
33
			switch ($route_path[3]) {
34
				/**
35
				 * Get dependent packages for module
36
				 */
37
				case 'dependent_packages':
38
					return static::get_dependent_packages_for_module($route_path[2]);
39
				/**
40
				 * Get dependencies for module (packages, databases, storages)
41
				 */
42
				case 'dependencies':
43
					return static::get_dependencies_for_module($route_path[2]);
44
				/**
45
				 * Get dependencies for module during update
46
				 */
47
				case 'update_dependencies':
48
					return static::get_update_dependencies_for_module($route_path[2]);
49
				/**
50
				 * Get mapping of named module's databases to indexes of system databases
51
				 */
52
				case 'db':
53
					return static::get_module_databases($route_path[2]);
54
				/**
55
				 * Get mapping of named module's storages to indexes of system storages
56
				 */
57
				case 'storage':
58
					return static::get_module_storages($route_path[2]);
59
				default:
60
					throw new ExitException(400);
61
			}
62
		} elseif ($Request->route_path(2) == 'default') {
63
			/**
64
			 * Get current default module
65
			 */
66
			return static::get_default_module();
67
		} else {
68
			/**
69
			 * Get array of modules in extended form
70
			 */
71
			return static::get_modules_list();
72
		}
73
	}
74
	/**
75
	 * @param string $module
76
	 *
77
	 * @return string[][]
78
	 *
79
	 * @throws ExitException
80
	 */
81
	protected static function get_dependent_packages_for_module ($module) {
82
		if (!Config::instance()->module($module)) {
83
			throw new ExitException(404);
84
		}
85
		$meta_file = MODULES."/$module/meta.json";
86
		return file_exists($meta_file) ? Packages_dependencies::get_dependent_packages(file_get_json($meta_file)) : [];
87
	}
88
	/**
89
	 * @param string $module
90
	 *
91
	 * @return array
92
	 *
93
	 * @throws ExitException
94
	 */
95
	protected static function get_dependencies_for_module ($module) {
96
		if (!Config::instance()->module($module)) {
97
			throw new ExitException(404);
98
		}
99
		$meta_file = MODULES."/$module/meta.json";
100
		return file_exists($meta_file) ? Packages_dependencies::get_dependencies(file_get_json($meta_file)) : [];
101
	}
102
	/**
103
	 * @param string $module
104
	 *
105
	 * @return array
106
	 *
107
	 * @throws ExitException
108
	 */
109
	protected static function get_update_dependencies_for_module ($module) {
110
		if (!Config::instance()->module($module)) {
111
			throw new ExitException(404);
112
		}
113
		$tmp_location = TEMP.'/System/admin/'.Session::instance()->get_id().'.phar';
0 ignored issues
show
Bug introduced by
Are you sure cs\Session::instance()->get_id() of type false|string can be used in concatenation? ( Ignorable by Annotation )

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

113
		$tmp_location = TEMP.'/System/admin/'./** @scrutinizer ignore-type */ Session::instance()->get_id().'.phar';
Loading history...
114
		$tmp_dir      = "phar://$tmp_location";
115
		if (
116
			!file_exists(MODULES."/$module/meta.json") ||
117
			!file_exists("$tmp_dir/meta.json")
118
		) {
119
			throw new ExitException(400);
120
		}
121
		$new_meta = file_get_json("$tmp_dir/meta.json");
122
		if (!static::is_same_module($new_meta, $module)) {
123
			throw new ExitException(Language::prefix('system_admin_modules_')->this_is_not_module_installer_file, 400);
0 ignored issues
show
Bug Best Practice introduced by
The property this_is_not_module_installer_file does not exist on cs\Language\Prefix. Since you implemented __get, consider adding a @property annotation.
Loading history...
124
		}
125
		return Packages_dependencies::get_dependencies($new_meta, true);
126
	}
127
	/**
128
	 * @param array  $meta
129
	 * @param string $module
130
	 *
131
	 * @return bool
132
	 */
133
	protected static function is_same_module ($meta, $module) {
134
		return $meta['category'] == 'modules' && $meta['package'] == $module;
135
	}
136
	/**
137
	 * @param string $module
138
	 *
139
	 * @return array
140
	 *
141
	 * @throws ExitException
142
	 */
143
	protected static function get_module_databases ($module) {
144
		$Config = Config::instance();
145
		if (!isset($Config->components['modules'][$module]['db'])) {
146
			throw new ExitException(404);
147
		}
148
		return $Config->components['modules'][$module]['db'];
149
	}
150
	/**
151
	 * @param string $module
152
	 *
153
	 * @return array
154
	 *
155
	 * @throws ExitException
156
	 */
157
	protected static function get_module_storages ($module) {
158
		$Config = Config::instance();
159
		if (!isset($Config->components['modules'][$module]['storage'])) {
160
			throw new ExitException(404);
161
		}
162
		return $Config->components['modules'][$module]['storage'];
163
	}
164
	protected static function get_modules_list () {
165
		$Config       = Config::instance();
166
		$modules_list = [];
167
		foreach ($Config->components['modules'] as $module_name => &$module_data) {
168
			$module = [
169
				'active'            => $module_data['active'],
170
				'name'              => $module_name,
171
				'has_user_section'  => file_exists_with_extension(MODULES."/$module_name/index", ['php', 'html', 'json']),
172
				'has_admin_section' => file_exists_with_extension(MODULES."/$module_name/admin/index", ['php', 'json'])
173
			];
174
			/**
175
			 * Check if API available
176
			 */
177
			static::check_module_feature_availability($module, 'readme', 'api');
178
			/**
179
			 * Check if readme available
180
			 */
181
			static::check_module_feature_availability($module, 'readme');
182
			/**
183
			 * Check if license available
184
			 */
185
			static::check_module_feature_availability($module, 'license');
186
			if (file_exists(MODULES."/$module_name/meta.json")) {
187
				$module['meta'] = file_get_json(MODULES."/$module_name/meta.json");
188
			}
189
			$modules_list[] = $module;
190
		}
191
		return $modules_list;
192
	}
193
	/**
194
	 * @param array  $module
195
	 * @param string $feature
196
	 * @param string $dir
197
	 */
198
	protected static function check_module_feature_availability (&$module, $feature, $dir = '') {
199
		/**
200
		 * Check if feature available
201
		 */
202
		$file = file_exists_with_extension(MODULES."/$module[name]/$dir/$feature", ['txt', 'html']);
203
		if ($file) {
204
			$module[$dir ?: $feature] = [
205
				'type'    => substr($file, -3) == 'txt' ? 'txt' : 'html',
206
				'content' => file_get_contents($file)
207
			];
208
		} elseif ($dir && is_dir(MODULES."/$module[name]/$dir")) {
209
			$module[$dir ?: $feature] = [];
210
		}
211
	}
212
	/**
213
	 * @return string
214
	 */
215
	protected static function get_default_module () {
216
		return Config::instance()->core['default_module'];
217
	}
218
	/**
219
	 * @param \cs\Request $Request
220
	 *
221
	 * @throws ExitException
222
	 */
223
	public static function admin_modules_put ($Request) {
224
		if ($Request->route_path(3)) {
225
			$module = $Request->route_path[2];
226
			switch ($Request->route_path[3]) {
227
				/**
228
				 * Set mapping of named module's databases to indexes of system databases
229
				 */
230
				case 'db':
231
					static::set_module_databases($Request, $module);
232
					break;
233
				/**
234
				 * Set mapping of named module's storages to indexes of system storages
235
				 */
236
				case 'storage':
237
					static::set_module_storages($Request, $module);
238
					break;
239
				default:
240
					throw new ExitException(400);
241
			}
242
		} elseif ($Request->route_path(2) == 'default') {
243
			/**
244
			 * Set current default module
245
			 */
246
			static::set_default_module($Request->data('module'));
0 ignored issues
show
Bug introduced by
'module' of type string is incompatible with the type array<mixed,string[]>|string[] expected by parameter $name of cs\Request::data(). ( Ignorable by Annotation )

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

246
			static::set_default_module($Request->data(/** @scrutinizer ignore-type */ 'module'));
Loading history...
Bug introduced by
It seems like $Request->data('module') can also be of type array and array; however, parameter $module of cs\modules\System\api\Co...s::set_default_module() does only seem to accept string, 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

246
			static::set_default_module(/** @scrutinizer ignore-type */ $Request->data('module'));
Loading history...
247
		} else {
248
			throw new ExitException(400);
249
		}
250
	}
251
	/**
252
	 * @param \cs\Request $Request
253
	 * @param string      $module
254
	 *
255
	 * @throws ExitException
256
	 */
257
	protected static function set_module_databases ($Request, $module) {
258
		$Config          = Config::instance();
259
		$database_config = $Request->data('db');
0 ignored issues
show
Bug introduced by
'db' of type string is incompatible with the type array<mixed,string[]>|string[] expected by parameter $name of cs\Request::data(). ( Ignorable by Annotation )

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

259
		$database_config = $Request->data(/** @scrutinizer ignore-type */ 'db');
Loading history...
260
		if (!$database_config || !isset($Config->components['modules'][$module]['db'])) {
261
			throw new ExitException(404);
262
		}
263
		$Config->components['modules'][$module]['db'] = _int($database_config);
264
		static::admin_modules_save();
265
	}
266
	/**
267
	 * @param \cs\Request $Request
268
	 * @param string      $module
269
	 *
270
	 * @throws ExitException
271
	 */
272
	protected static function set_module_storages ($Request, $module) {
273
		$Config         = Config::instance();
274
		$storage_config = $Request->data('storage');
0 ignored issues
show
Bug introduced by
'storage' of type string is incompatible with the type array<mixed,string[]>|string[] expected by parameter $name of cs\Request::data(). ( Ignorable by Annotation )

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

274
		$storage_config = $Request->data(/** @scrutinizer ignore-type */ 'storage');
Loading history...
275
		if (!$storage_config || !isset($Config->components['modules'][$module]['storage'])) {
276
			throw new ExitException(404);
277
		}
278
		$Config->components['modules'][$module]['storage'] = _int($storage_config);
279
		static::admin_modules_save();
280
	}
281
	/**
282
	 * @param string $module
283
	 *
284
	 * @throws ExitException
285
	 */
286
	protected static function set_default_module ($module) {
287
		$Config = Config::instance();
288
		if (!Event::instance()->fire('admin/System/modules/default', ['name' => $module])) {
289
			throw new ExitException(500);
290
		}
291
		$Config->core['default_module'] = $module;
292
		static::admin_modules_save();
293
		if ($Config->core['default_module'] != $module) {
294
			throw new ExitException(400);
295
		}
296
	}
297
	/**
298
	 * Enable module
299
	 *
300
	 * Provides next events:
301
	 *  admin/System/modules/enable/before
302
	 *  ['name' => module_name]
303
	 *
304
	 *  admin/System/modules/enable/after
305
	 *  ['name' => module_name]
306
	 *
307
	 * @param \cs\Request $Request
308
	 *
309
	 * @throws ExitException
310
	 */
311
	public static function admin_modules_enable ($Request) {
312
		$Config = Config::instance();
313
		$module = $Request->route_path(2);
314
		if (!$Config->module($module)->disabled()) {
315
			throw new ExitException(400);
316
		}
317
		if (!Event::instance()->fire('admin/System/modules/enable/before', ['name' => $module])) {
318
			throw new ExitException(500);
319
		}
320
		$Config->components['modules'][$module]['active'] = Config\Module_Properties::ENABLED;
321
		static::admin_modules_save();
322
		Event::instance()->fire('admin/System/modules/enable/after', ['name' => $module]);
323
		static::admin_modules_cleanup();
324
	}
325
	protected static function admin_modules_cleanup () {
326
		clean_public_cache();
327
		$Cache = System_cache::instance();
328
		unset(
329
			$Cache->functionality,
0 ignored issues
show
Bug Best Practice introduced by
The property functionality does not exist on cs\Cache. Since you implemented __get, consider adding a @property annotation.
Loading history...
330
			$Cache->languages
0 ignored issues
show
Bug Best Practice introduced by
The property languages does not exist on cs\Cache. Since you implemented __get, consider adding a @property annotation.
Loading history...
331
		);
332
		__classes_clean_cache();
333
	}
334
	/**
335
	 * Disable module
336
	 *
337
	 * Provides next events:
338
	 *  admin/System/modules/disable/before
339
	 *  ['name' => module_name]
340
	 *
341
	 *  admin/System/modules/disable/after
342
	 *  ['name' => module_name]
343
	 *
344
	 * @param \cs\Request $Request
345
	 *
346
	 * @throws ExitException
347
	 */
348
	public static function admin_modules_disable ($Request) {
349
		$Config = Config::instance();
350
		$module = $Request->route_path(2);
351
		if (
352
			$module == Config::SYSTEM_MODULE ||
353
			$Config->core['default_module'] == $module ||
354
			!$Config->module($module)->enabled()
355
		) {
356
			throw new ExitException(400);
357
		}
358
		static::admin_modules_disable_internal($Config, $module);
359
	}
360
	/**
361
	 * @param Config $Config
362
	 * @param string $module
363
	 *
364
	 * @throws ExitException
365
	 */
366
	protected static function admin_modules_disable_internal ($Config, $module) {
367
		if (!Event::instance()->fire('admin/System/modules/disable/before', ['name' => $module])) {
368
			throw new ExitException(500);
369
		}
370
		$Config->components['modules'][$module]['active'] = Config\Module_Properties::DISABLED;
371
		static::admin_modules_save();
372
		Event::instance()->fire('admin/System/modules/disable/after', ['name' => $module]);
373
		static::admin_modules_cleanup();
374
	}
375
	/**
376
	 * Install module
377
	 *
378
	 * Provides next events:
379
	 *  admin/System/modules/install/before
380
	 *  ['name' => module_name]
381
	 *
382
	 *  admin/System/modules/install/after
383
	 *  ['name' => module_name]
384
	 *
385
	 * @param \cs\Request $Request
386
	 *
387
	 * @throws ExitException
388
	 */
389
	public static function admin_modules_install ($Request) {
390
		$Config = Config::instance();
391
		$module = $Request->route_path(2);
392
		if (!$Config->module($module)->uninstalled()) {
393
			throw new ExitException(400);
394
		}
395
		if (!Event::instance()->fire('admin/System/modules/install/before', ['name' => $module])) {
396
			throw new ExitException(500);
397
		}
398
		$module_data     = &$Config->components['modules'][$module];
399
		$database_config = $Request->data('db');
0 ignored issues
show
Bug introduced by
'db' of type string is incompatible with the type array<mixed,string[]>|string[] expected by parameter $name of cs\Request::data(). ( Ignorable by Annotation )

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

399
		$database_config = $Request->data(/** @scrutinizer ignore-type */ 'db');
Loading history...
400
		if ($database_config) {
401
			$module_data['db'] = _int($database_config);
402
			Packages_manipulation::execute_sql_from_directory(MODULES."/$module/meta/install_db", $module_data['db']);
403
		}
404
		$storage_config = $Request->data('storage');
405
		if ($storage_config) {
406
			$module_data['storage'] = _int($storage_config);
407
		}
408
		$module_data['active'] = Config\Module_Properties::DISABLED;
409
		static::admin_modules_save();
410
		Event::instance()->fire('admin/System/modules/install/after', ['name' => $module]);
411
		static::admin_modules_cleanup();
412
	}
413
	/**
414
	 * Uninstall module
415
	 *
416
	 * Provides next events:
417
	 *  admin/System/modules/uninstall/before
418
	 *  ['name' => module_name]
419
	 *
420
	 *  admin/System/modules/uninstall/after
421
	 *  ['name' => module_name]
422
	 *
423
	 * @param \cs\Request $Request
424
	 *
425
	 * @throws ExitException
426
	 */
427
	public static function admin_modules_uninstall ($Request) {
428
		$Config  = Config::instance();
429
		$module  = $Request->route_path(2);
430
		$modules = &$Config->components['modules'];
431
		/**
432
		 * Do not allow to uninstall enabled module, it should be explicitly disabled first
433
		 */
434
		if (!$Config->module($module)->disabled()) {
435
			throw new ExitException(400);
436
		}
437
		if (!Event::instance()->fire('admin/System/modules/uninstall/before', ['name' => $module])) {
438
			throw new ExitException(500);
439
		}
440
		$module_data = &$modules[$module];
441
		if (isset($module_data['db'])) {
442
			Packages_manipulation::execute_sql_from_directory(MODULES."/$module/meta/uninstall_db", $module_data['db']);
443
		}
444
		static::delete_permissions_for_module($module);
445
		$modules[$module] = ['active' => Config\Module_Properties::UNINSTALLED];
446
		static::admin_modules_save();
447
		Event::instance()->fire('admin/System/modules/uninstall/after', ['name' => $module]);
448
		static::admin_modules_cleanup();
449
	}
450
	/**
451
	 * @param string $module
452
	 */
453
	protected static function delete_permissions_for_module ($module) {
454
		$Permission      = Permission::instance();
455
		$permissions_ids = array_merge(
456
			$Permission->get(null, $module),
0 ignored issues
show
Bug introduced by
It seems like $Permission->get(null, $module) can also be of type false; however, parameter $array1 of array_merge() does only seem to accept array, 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

456
			/** @scrutinizer ignore-type */ $Permission->get(null, $module),
Loading history...
457
			$Permission->get(null, "admin/$module"),
0 ignored issues
show
Bug introduced by
It seems like $Permission->get(null, EncapsedNode) can also be of type false; however, parameter $array2 of array_merge() does only seem to accept null|array, 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

457
			/** @scrutinizer ignore-type */ $Permission->get(null, "admin/$module"),
Loading history...
458
			$Permission->get(null, "api/$module")
0 ignored issues
show
Bug introduced by
It seems like $Permission->get(null, EncapsedNode) can also be of type false; however, parameter $_ of array_merge() does only seem to accept array, 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

458
			/** @scrutinizer ignore-type */ $Permission->get(null, "api/$module")
Loading history...
459
		);
460
		if (!empty($permissions_ids)) {
461
			$Permission->del(
462
				array_column($permissions_ids, 'id')
463
			);
464
		}
465
	}
466
	/**
467
	 * Extract uploaded module
468
	 *
469
	 * @throws ExitException
470
	 */
471
	public static function admin_modules_extract () {
472
		$Config       = Config::instance();
473
		$L            = Language::prefix('system_admin_modules_');
474
		$tmp_location = TEMP.'/System/admin/'.Session::instance()->get_id().'.phar';
0 ignored issues
show
Bug introduced by
Are you sure cs\Session::instance()->get_id() of type false|string can be used in concatenation? ( Ignorable by Annotation )

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

474
		$tmp_location = TEMP.'/System/admin/'./** @scrutinizer ignore-type */ Session::instance()->get_id().'.phar';
Loading history...
475
		$tmp_dir      = "phar://$tmp_location";
476
		if (
477
			!file_exists($tmp_location) ||
478
			!file_exists("$tmp_dir/meta.json")
479
		) {
480
			throw new ExitException(400);
481
		}
482
		$new_meta = file_get_json("$tmp_dir/meta.json");
483
		if ($new_meta['category'] !== 'modules') {
484
			throw new ExitException($L->this_is_not_module_installer_file, 400);
0 ignored issues
show
Bug Best Practice introduced by
The property this_is_not_module_installer_file does not exist on cs\Language\Prefix. Since you implemented __get, consider adding a @property annotation.
Loading history...
485
		}
486
		if (!Packages_manipulation::install_extract(MODULES."/$new_meta[package]", $tmp_location)) {
487
			throw new ExitException($L->module_files_unpacking_error, 500);
0 ignored issues
show
Bug Best Practice introduced by
The property module_files_unpacking_error does not exist on cs\Language\Prefix. Since you implemented __get, consider adding a @property annotation.
Loading history...
488
		}
489
		$Config->components['modules'][$new_meta['package']] = ['active' => Config\Module_Properties::UNINSTALLED];
490
		ksort($Config->components['modules'], SORT_STRING | SORT_FLAG_CASE);
491
		static::admin_modules_save();
492
		static::admin_modules_cleanup();
493
	}
494
	/**
495
	 * Update module (or system if module name is System)
496
	 *
497
	 * @param \cs\Request $Request
498
	 *
499
	 * @throws ExitException
500
	 */
501
	public static function admin_modules_update ($Request) {
502
		$module = $Request->route_path(2);
503
		if (!Config::instance()->module($module)) {
504
			throw new ExitException(404);
505
		}
506
		$tmp_location = TEMP.'/System/admin/'.Session::instance()->get_id().'.phar';
0 ignored issues
show
Bug introduced by
Are you sure cs\Session::instance()->get_id() of type false|string can be used in concatenation? ( Ignorable by Annotation )

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

506
		$tmp_location = TEMP.'/System/admin/'./** @scrutinizer ignore-type */ Session::instance()->get_id().'.phar';
Loading history...
507
		$tmp_dir      = "phar://$tmp_location";
508
		$module_dir   = MODULES."/$module";
509
		if (
510
			!file_exists($tmp_location) ||
511
			!file_exists("$module_dir/meta.json") ||
512
			!file_exists("$tmp_dir/meta.json")
513
		) {
514
			throw new ExitException(400);
515
		}
516
		$existing_meta = file_get_json("$module_dir/meta.json");
517
		$new_meta      = file_get_json("$tmp_dir/meta.json");
518
		if ($module == Config::SYSTEM_MODULE) {
519
			static::update_system($module, $existing_meta, $new_meta, $tmp_location);
520
			// Clean the whole cache during system update
521
			System_cache::instance()->clean();
522
		} else {
523
			static::update_module($module, $existing_meta, $new_meta, $tmp_location, $Request);
524
		}
525
		static::admin_modules_cleanup();
526
	}
527
	/**
528
	 * Provides next events:
529
	 *  admin/System/modules/update/before
530
	 *  ['name' => module_name]
531
	 *
532
	 *  admin/System/modules/update/after
533
	 *  ['name' => module_name]
534
	 *
535
	 * @param string      $module
536
	 * @param array       $existing_meta
537
	 * @param array       $new_meta
538
	 * @param string      $tmp_location
539
	 * @param \cs\Request $Request
540
	 *
541
	 * @throws ExitException
542
	 */
543
	protected static function update_module ($module, $existing_meta, $new_meta, $tmp_location, $Request) {
544
		$Config     = Config::instance();
545
		$L          = Language::prefix('system_admin_modules_');
546
		$module_dir = MODULES."/$module";
547
		$enabled    = $Config->module($module)->enabled();
548
		// If module is currently enabled - disable it temporary
549
		if ($enabled) {
550
			static::admin_modules_disable_internal($Config, $module);
551
		}
552
		if (!static::is_same_module($new_meta, $module)) {
553
			throw new ExitException($L->this_is_not_module_installer_file, 400);
0 ignored issues
show
Bug Best Practice introduced by
The property this_is_not_module_installer_file does not exist on cs\Language\Prefix. Since you implemented __get, consider adding a @property annotation.
Loading history...
554
		}
555
		if (!Event::instance()->fire('admin/System/modules/update/before', ['name' => $module])) {
556
			throw new ExitException(500);
557
		}
558
		if (!is_writable($module_dir)) {
559
			throw new ExitException($L->cant_unpack_module_no_write_permissions, 500);
0 ignored issues
show
Bug Best Practice introduced by
The property cant_unpack_module_no_write_permissions does not exist on cs\Language\Prefix. Since you implemented __get, consider adding a @property annotation.
Loading history...
560
		}
561
		if (!Packages_manipulation::update_extract($module_dir, $tmp_location)) {
562
			throw new ExitException($L->module_files_unpacking_error, 500);
0 ignored issues
show
Bug Best Practice introduced by
The property module_files_unpacking_error does not exist on cs\Language\Prefix. Since you implemented __get, consider adding a @property annotation.
Loading history...
563
		}
564
		$module_data = $Config->components['modules'][$module];
565
		// Run PHP update scripts and SQL queries if any
566
		Packages_manipulation::update_php_sql($module_dir, $existing_meta['version'], isset($module_data['db']) ? $module_data['db'] : null);
567
		Event::instance()->fire('admin/System/modules/update/after', ['name' => $module]);
568
		// If module was enabled before update - enable it back
569
		if ($enabled) {
570
			static::admin_modules_enable($Request);
571
		}
572
	}
573
	/**
574
	 * Provides next events:
575
	 *  admin/System/modules/update_system/before
576
	 *
577
	 *  admin/System/modules/update_system/after
578
	 *
579
	 * @param string $module
580
	 * @param array  $existing_meta
581
	 * @param array  $new_meta
582
	 * @param string $tmp_location
583
	 *
584
	 * @throws ExitException
585
	 */
586
	protected static function update_system ($module, $existing_meta, $new_meta, $tmp_location) {
587
		$Config     = Config::instance();
588
		$L          = Language::prefix('system_admin_modules_');
589
		$module_dir = MODULES."/$module";
590
		/**
591
		 * Temporary close site
592
		 */
593
		$site_mode                 = $Config->core['site_mode'];
594
		$Config->core['site_mode'] = 0;
595
		static::admin_modules_save();
596
		if (!static::is_same_module($new_meta, Config::SYSTEM_MODULE)) {
597
			throw new ExitException($L->this_is_not_system_installer_file, 400);
0 ignored issues
show
Bug Best Practice introduced by
The property this_is_not_system_installer_file does not exist on cs\Language\Prefix. Since you implemented __get, consider adding a @property annotation.
Loading history...
598
		}
599
		if (!Event::instance()->fire('admin/System/modules/update_system/before')) {
600
			throw new ExitException(500);
601
		}
602
		if (!Packages_manipulation::update_extract(DIR, $tmp_location, DIR.'/core', $module_dir)) {
603
			throw new ExitException($L->system_files_unpacking_error, 500);
0 ignored issues
show
Bug Best Practice introduced by
The property system_files_unpacking_error does not exist on cs\Language\Prefix. Since you implemented __get, consider adding a @property annotation.
Loading history...
604
		}
605
		$module_data = $Config->components['modules'][$module];
606
		// Run PHP update scripts and SQL queries if any
607
		Packages_manipulation::update_php_sql($module_dir, $existing_meta['version'], isset($module_data['db']) ? $module_data['db'] : null);
608
		Event::instance()->fire('admin/System/modules/update_system/after');
609
		/**
610
		 * Restore previous site mode
611
		 */
612
		$Config->core['site_mode'] = $site_mode;
613
		static::admin_modules_save();
614
		static::admin_modules_cleanup();
615
	}
616
	/**
617
	 * Delete module completely
618
	 *
619
	 * @param \cs\Request $Request
620
	 *
621
	 * @throws ExitException
622
	 */
623
	public static function admin_modules_delete ($Request) {
624
		$Config = Config::instance();
625
		$module = $Request->route_path(2);
626
		if (!$Config->module($module)->uninstalled()) {
627
			throw new ExitException(400);
628
		}
629
		if (!rmdir_recursive(MODULES."/$module")) {
630
			throw new ExitException(500);
631
		}
632
		unset($Config->components['modules'][$module]);
633
		static::admin_modules_save();
634
	}
635
	/**
636
	 * Update information about present modules
637
	 *
638
	 * @throws ExitException
639
	 */
640
	public static function admin_modules_update_list () {
641
		$Config = Config::instance();
642
		/**
643
		 * List of currently presented modules in file system
644
		 */
645
		$modules_in_fs = get_files_list(MODULES, false, 'd');
646
		$modules_list  = array_fill_keys(
647
			$modules_in_fs,
648
			[
649
				'active'  => Config\Module_Properties::UNINSTALLED,
650
				'db'      => [],
651
				'storage' => []
652
			]
653
		);
654
		/**
655
		 * Already known modules
656
		 */
657
		$modules       = &$Config->components['modules'];
658
		$known_modules = array_keys($modules);
659
		if ($modules_in_fs != $known_modules) {
660
			/**
661
			 * Delete permissions of modules that are mot present anymore
662
			 */
663
			foreach ($known_modules as $module) {
664
				if (!isset($modules_list[$module])) {
665
					static::delete_permissions_for_module($module);
666
				}
667
			}
668
			unset($module);
669
		}
670
		unset($modules_in_fs, $known_modules);
671
		$modules = array_merge($modules_list, array_intersect_key($modules, $modules_list));
672
		ksort($modules, SORT_STRING | SORT_FLAG_CASE);
673
		static::admin_modules_save();
674
		static::admin_modules_cleanup();
675
	}
676
	/**
677
	 * Save changes
678
	 *
679
	 * @throws ExitException
680
	 */
681
	protected static function admin_modules_save () {
682
		if (!Config::instance()->save()) {
683
			throw new ExitException(500);
684
		}
685
	}
686
}
687