modules::admin_modules_get()   C
last analyzed

Complexity

Conditions 8
Paths 8

Size

Total Lines 42
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 72

Importance

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

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

245
			static::set_default_module(/** @scrutinizer ignore-type */ $Request->data('module'));
Loading history...
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

245
			static::set_default_module($Request->data(/** @scrutinizer ignore-type */ 'module'));
Loading history...
246
		} else {
247
			throw new ExitException(400);
248
		}
249
	}
250
	/**
251
	 * @param \cs\Request $Request
252
	 * @param string      $module
253
	 *
254
	 * @throws ExitException
255
	 */
256
	protected static function set_module_databases ($Request, $module) {
257
		$Config          = Config::instance();
258
		$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

258
		$database_config = $Request->data(/** @scrutinizer ignore-type */ 'db');
Loading history...
259
		if (!$database_config || !isset($Config->components['modules'][$module]['db'])) {
260
			throw new ExitException(404);
261
		}
262
		$Config->components['modules'][$module]['db'] = _int($database_config);
263
		static::admin_modules_save();
264
	}
265
	/**
266
	 * @param \cs\Request $Request
267
	 * @param string      $module
268
	 *
269
	 * @throws ExitException
270
	 */
271
	protected static function set_module_storages ($Request, $module) {
272
		$Config         = Config::instance();
273
		$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

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

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

455
			/** @scrutinizer ignore-type */ $Permission->get(null, $module),
Loading history...
456
			$Permission->get(null, "admin/$module"),
0 ignored issues
show
Bug introduced by
It seems like $Permission->get(null, 'admin/'.$module) 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

456
			/** @scrutinizer ignore-type */ $Permission->get(null, "admin/$module"),
Loading history...
457
			$Permission->get(null, "api/$module")
0 ignored issues
show
Bug introduced by
It seems like $Permission->get(null, 'api/'.$module) 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

457
			/** @scrutinizer ignore-type */ $Permission->get(null, "api/$module")
Loading history...
458
		);
459
		if (!empty($permissions_ids)) {
460
			$Permission->del(
461
				array_column($permissions_ids, 'id')
462
			);
463
		}
464
	}
465
	/**
466
	 * Extract uploaded module
467
	 *
468
	 * @throws ExitException
469
	 */
470
	public static function admin_modules_extract () {
471
		$Config       = Config::instance();
472
		$L            = Language::prefix('system_admin_modules_');
473
		$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

473
		$tmp_location = TEMP.'/System/admin/'./** @scrutinizer ignore-type */ Session::instance()->get_id().'.phar';
Loading history...
474
		$tmp_dir      = "phar://$tmp_location";
475
		if (
476
			!file_exists($tmp_location) ||
477
			!file_exists("$tmp_dir/meta.json")
478
		) {
479
			throw new ExitException(400);
480
		}
481
		$new_meta = file_get_json("$tmp_dir/meta.json");
482
		if ($new_meta['category'] !== 'modules') {
483
			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...
484
		}
485
		if (!Packages_manipulation::install_extract(MODULES."/$new_meta[package]", $tmp_location)) {
486
			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...
487
		}
488
		$Config->components['modules'][$new_meta['package']] = ['active' => Config\Module_Properties::UNINSTALLED];
489
		ksort($Config->components['modules'], SORT_STRING | SORT_FLAG_CASE);
490
		static::admin_modules_save();
491
		static::admin_modules_cleanup();
492
	}
493
	/**
494
	 * Update module (or system if module name is System)
495
	 *
496
	 * @param \cs\Request $Request
497
	 *
498
	 * @throws ExitException
499
	 */
500
	public static function admin_modules_update ($Request) {
501
		$module = $Request->route_path(2);
502
		if (!Config::instance()->module($module)) {
503
			throw new ExitException(404);
504
		}
505
		$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

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