Completed
Push — master ( ad5c29...69a790 )
by Nazar
05:17
created

execute_sql_from_directory()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

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