Completed
Push — master ( 1322e1...f9aba3 )
by Nazar
05:55
created

Packages_manipulation::generic_extract()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3.0175

Importance

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