Completed
Push — master ( 835ae4...674f63 )
by Nazar
04:52
created

Packages_manipulation::install_extract()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 29
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 5.0488

Importance

Changes 0
Metric Value
cc 5
eloc 20
nc 3
nop 2
dl 0
loc 29
ccs 14
cts 16
cp 0.875
crap 5.0488
rs 8.439
c 0
b 0
f 0
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-2016, Nazar Mokrynskyi
8
 * @license    MIT License, see license.txt
9
 */
10
namespace cs\modules\System;
11
use
12
	cs\Config,
13
	cs\Core,
14
	cs\DB;
15
16
/**
17
 * Utility functions, necessary during packages manipulation (installation/uninstallation, enabling/disabling)
18
 */
19
class Packages_manipulation {
20
	/**
21
	 * Generic extraction of files from phar distributive for CleverStyle Framework (components installation)
22
	 *
23
	 * @param string $target_directory
24
	 * @param string $source_phar Will be removed after extraction
25
	 *
26
	 * @return bool
27
	 */
28 2
	public static function install_extract ($target_directory, $source_phar) {
29
		/** @noinspection MkdirRaceConditionInspection */
30 2
		if (!mkdir($target_directory, 0770)) {
31 2
			return false;
32
		}
33 2
		$tmp_dir   = "phar://$source_phar";
34 2
		$fs        = file_get_json("$tmp_dir/fs.json");
35 2
		$extracted = array_filter(
36
			array_map(
37
				function ($index, $file) use ($tmp_dir, $target_directory) {
38
					if (
39 2
						!@mkdir(dirname("$target_directory/$file"), 0770, true) &&
40 2
						!is_dir(dirname("$target_directory/$file"))
41
					) {
42
						return false;
43
					}
44 2
					return copy("$tmp_dir/fs/$index", "$target_directory/$file");
45 2
				},
46
				$fs,
47
				array_keys($fs)
48
			)
49
		);
50 2
		unlink($source_phar);
51 2
		if (count($extracted) === count($fs)) {
52 2
			file_put_json("$target_directory/fs.json", array_keys($fs));
53 2
			return true;
54
		}
55
		return false;
56
	}
57
	/**
58
	 * Generic extraction of files from phar distributive for CleverStyle Framework (system and components update)
59
	 *
60
	 * @param string      $target_directory
61
	 * @param string      $source_phar             Will be removed after extraction
62
	 * @param null|string $fs_location_directory   Defaults to `$target_directory`
63
	 * @param null|string $meta_location_directory Defaults to `$target_directory`
64
	 *
65
	 * @return bool
66
	 */
67 2
	public static function update_extract ($target_directory, $source_phar, $fs_location_directory = null, $meta_location_directory = null) {
68 2
		$fs_location_directory   = $fs_location_directory ?: $target_directory;
69 2
		$meta_location_directory = $meta_location_directory ?: $target_directory;
70
		/**
71
		 * Backup some necessary information about current version
72
		 */
73 2
		copy("$fs_location_directory/fs.json", "$fs_location_directory/fs_backup.json");
74 2
		copy("$meta_location_directory/meta.json", "$meta_location_directory/meta_backup.json");
75
		/**
76
		 * Extracting new versions of files
77
		 */
78 2
		$tmp_dir   = "phar://$source_phar";
79 2
		$fs        = file_get_json("$tmp_dir/fs.json");
80 2
		$extracted = array_filter(
81
			array_map(
82
				function ($index, $file) use ($tmp_dir, $target_directory) {
83
					if (
84 2
						!@mkdir(dirname("$target_directory/$file"), 0770, true) &&
85 2
						!is_dir(dirname("$target_directory/$file"))
86
					) {
87
						return false;
88
					}
89 2
					return copy("$tmp_dir/fs/$index", "$target_directory/$file");
90 2
				},
91
				$fs,
92
				array_keys($fs)
93
			)
94
		);
95 2
		if (count($extracted) !== count($fs)) {
96 2
			return false;
97
		}
98 2
		unlink($source_phar);
99 2
		unset($tmp_dir, $extracted);
100 2
		$fs = array_keys($fs);
101
		/**
102
		 * Removing of old unnecessary files and directories
103
		 */
104
		foreach (
105 2
			array_diff(
106 2
				file_get_json("$fs_location_directory/fs_backup.json"),
107
				$fs
108
			) as $file
109
		) {
110 2
			$file = "$target_directory/$file";
111 2
			if (is_writable($file)) {
112 2
				unlink($file);
113
				// Recursively remove all empty parent directories
114 2
				while (!get_files_list($file = dirname($file), false, 'fd')) {
115 2
					rmdir($file);
116
				}
117
			}
118
		}
119 2
		unset($file, $dir);
120 2
		file_put_json("$fs_location_directory/fs.json", $fs);
121 2
		clearstatcache(true);
122 2
		if (function_exists('opcache_reset')) {
123 2
			opcache_reset();
124
		}
125 2
		return true;
126
	}
127
	/**
128
	 * Generic update for CleverStyle Framework (system and components), runs PHP scripts and does DB migrations after extracting of new distributive
129
	 *
130
	 * @param string     $target_directory
131
	 * @param string     $old_version
132
	 * @param array|null $db_array `$Config->components['modules'][$module]['db']` if module or system
133
	 *
134
	 * @throws \cs\ExitException
135
	 */
136 2
	public static function update_php_sql ($target_directory, $old_version, $db_array = null) {
137 2
		foreach (self::get_update_versions($target_directory) as $version) {
138 2
			if (version_compare($old_version, $version, '<')) {
139
				/**
140
				 * PHP update script
141
				 */
142 2
				_include_once("$target_directory/meta/update/$version.php", false);
143
				/**
144
				 * Database update
145
				 */
146 2
				if ($db_array) {
147 2
					self::execute_sql_from_directory("$target_directory/meta/update_db", $db_array, $version);
148
				}
149
			}
150
		}
151 2
	}
152
	/**
153
	 * @param string $target_directory
154
	 *
155
	 * @return string[]
156
	 */
157 2
	protected static function get_update_versions ($target_directory) {
158 2
		$update_versions = _mb_substr(get_files_list("$target_directory/meta/update"), 0, -4) ?: [];
159 2
		foreach (get_files_list("$target_directory/meta/update_db", false, 'd') ?: [] as $db) {
160
			/** @noinspection SlowArrayOperationsInLoopInspection */
161 2
			$update_versions = array_merge(
162
				$update_versions,
163 2
				get_files_list("$target_directory/meta/update_db/$db", false, 'd') ?: []
164
			);
165
		}
166 2
		$update_versions = array_unique($update_versions);
167 2
		usort($update_versions, 'version_compare');
168 2
		return $update_versions;
169
	}
170
	/**
171
	 * @param string $directory        Base path to SQL files
172
	 * @param array  $db_configuration Array in form [$db_name => $index]
173
	 * @param string $version          In case when we are working with update script we might have version subdirectory
174
	 *
175
	 * @throws \cs\ExitException
176
	 */
177 2
	public static function execute_sql_from_directory ($directory, $db_configuration, $version = '') {
178 2
		$Config = Config::instance();
179 2
		$Core   = Core::instance();
180 2
		$db     = DB::instance();
181 2
		time_limit_pause();
182 2
		foreach ($db_configuration as $db_name => $index) {
183 2
			$db_type  = $index == 0 ? $Core->db_type : $Config->db[$index]['type'];
184 2
			$sql_file = "$directory/$db_name/$version/$db_type.sql";
185 2
			if (file_exists($sql_file)) {
186
				/** @noinspection ExceptionsAnnotatingAndHandlingInspection */
187 2
				$db->db_prime($index)->transaction(
188 2
					function ($cdb) use ($sql_file) {
189
						/**
190
						 * @var DB\_Abstract $cdb
191
						 */
192 2
						$cdb->q(
193 2
							explode(';', file_get_contents($sql_file))
194
						);
195 2
					}
196
				);
197
			}
198
		}
199 2
		time_limit_pause(false);
200 2
	}
201
}
202