PluginProbe
Redirection / 4.1
Redirection v4.1
5.10.0 5.9.0 5.8.1 5.8.0 3.7.2 3.7.3 4.0 4.0.1 4.1 4.1.1 4.2 4.2.1 4.2.2 4.2.3 4.3 4.3.1 4.3.2 4.3.3 4.4 4.4.1 4.4.2 4.5 4.5.1 4.6.2 4.7.1 All 130 releases
redirection / database / database-status.php

database-status.php in Redirection 4.1, at database/database-status.php

341 lines 8.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class Red_Database_Status {
4 // Used in < 3.7 versions of Redirection, but since migrated to general settings
5 const OLD_DB_VERSION = 'redirection_version';
6 const DB_UPGRADE_STAGE = 'redirection_database_stage';
7
8 const RESULT_OK = 'ok';
9 const RESULT_ERROR = 'error';
10
11 const STATUS_OK = 'ok';
12 const STATUS_NEED_INSTALL = 'need-install';
13 const STATUS_NEED_UPDATING = 'need-update';
14 const STATUS_FINISHED_INSTALL = 'finish-install';
15 const STATUS_FINISHED_UPDATING = 'finish-update';
16
17 private $stage = false;
18 private $stages = [];
19
20 private $status = false;
21 private $result = false;
22 private $reason = false;
23 private $debug = [];
24
25 public function __construct() {
26 $this->status = self::STATUS_OK;
27
28 if ( $this->needs_installing() ) {
29 $this->status = self::STATUS_NEED_INSTALL;
30 } elseif ( $this->needs_updating() ) {
31 $this->status = self::STATUS_NEED_UPDATING;
32 }
33
34 $info = get_option( self::DB_UPGRADE_STAGE );
35 if ( $info ) {
36 $this->stage = isset( $info['stage'] ) ? $info['stage'] : false;
37 $this->stages = isset( $info['stages'] ) ? $info['stages'] : [];
38 $this->status = isset( $info['status'] ) ? $info['status'] : false;
39 }
40 }
41
42 /**
43 * Does the database need install
44 *
45 * @return bool true if needs installing, false otherwise
46 */
47 public function needs_installing() {
48 $settings = red_get_options();
49
50 if ( $settings['database'] === '' && $this->get_old_version() === false ) {
51 return true;
52 }
53
54 return false;
55 }
56
57 /**
58 * Does the current database need updating to the target
59 *
60 * @return bool true if needs updating, false otherwise
61 */
62 public function needs_updating() {
63 // We need updating if we don't need to install, and the current version is less than target version
64 if ( $this->needs_installing() === false && version_compare( $this->get_current_version(), REDIRECTION_DB_VERSION, '<' ) ) {
65 return true;
66 }
67
68 // Also if we're still in the process of upgrading
69 if ( $this->get_current_stage() ) {
70 return true;
71 }
72
73 return false;
74 }
75
76 /**
77 * Get current database version
78 *
79 * @return string Current database version
80 */
81 public function get_current_version() {
82 $settings = red_get_options();
83
84 if ( $settings['database'] !== '' ) {
85 return $settings['database'];
86 } elseif ( $this->get_old_version() !== false ) {
87 $version = $this->get_old_version();
88
89 // Upgrade the old value
90 red_set_options( array( 'database' => $version ) );
91 delete_option( self::OLD_DB_VERSION );
92 return $version;
93 }
94
95 return '';
96 }
97
98 private function get_old_version() {
99 return get_option( self::OLD_DB_VERSION );
100 }
101
102 public function check_tables_exist() {
103 $latest = Red_Database::get_latest_database();
104 $missing = $latest->get_missing_tables();
105
106 // No tables installed - do a fresh install
107 if ( count( $missing ) === count( $latest->get_all_tables() ) ) {
108 delete_option( Red_Database_Status::OLD_DB_VERSION );
109 red_set_options( [ 'database' => '' ] );
110 $this->status = self::STATUS_NEED_INSTALL;
111 $this->stop_update();
112 } elseif ( count( $missing ) > 0 && version_compare( $this->get_current_version(), '2.3.3', 'ge' ) ) {
113 // Some tables are missing - try and fill them in
114 $latest->install();
115 }
116 }
117
118 /**
119 * Does the current database support a particular version
120 *
121 * @param string $version Target version
122 * @return bool true if supported, false otherwise
123 */
124 public function does_support( $version ) {
125 return version_compare( $this->get_current_version(), $version, 'ge' );
126 }
127
128 public function is_error() {
129 return $this->result === self::RESULT_ERROR;
130 }
131
132 public function set_error( $error ) {
133 global $wpdb;
134
135 $this->result = self::RESULT_ERROR;
136 $this->reason = str_replace( "\t", ' ', $error );
137
138 if ( $wpdb->last_error ) {
139 $this->debug[] = $wpdb->last_error;
140 }
141
142 $latest = Red_Database::get_latest_database();
143 $this->debug = array_merge( $this->debug, $latest->get_table_schema() );
144 $this->debug[] = 'Stage: ' . $this->get_current_stage();
145 }
146
147 public function set_ok( $reason ) {
148 $this->reason = $reason;
149 $this->result = self::RESULT_OK;
150 $this->debug = [];
151 }
152
153 /**
154 * Stop current upgrade
155 */
156 public function stop_update() {
157 $this->stage = false;
158 $this->stages = [];
159 $this->debug = [];
160
161 delete_option( self::DB_UPGRADE_STAGE );
162 }
163
164 public function finish() {
165 $this->stop_update();
166
167 if ( $this->status === self::STATUS_NEED_INSTALL ) {
168 $this->status = self::STATUS_FINISHED_INSTALL;
169 } elseif ( $this->status === self::STATUS_NEED_UPDATING ) {
170 $this->status = self::STATUS_FINISHED_UPDATING;
171 }
172 }
173
174 /**
175 * Get current upgrade stage
176 * @return string|bool Current stage name, or false if not upgrading
177 */
178 public function get_current_stage() {
179 return $this->stage;
180 }
181
182 /**
183 * Move current stage on to the next
184 */
185 public function set_next_stage() {
186 $stage = $this->get_current_stage();
187
188 if ( $stage ) {
189 $stage = $this->get_next_stage( $stage );
190
191 // Save next position
192 if ( $stage ) {
193 $this->set_stage( $stage );
194 } else {
195 $this->finish();
196 }
197 }
198 }
199
200 /**
201 * Get current upgrade status
202 *
203 * @return array Database status array
204 */
205 public function get_json() {
206 // Base information
207 $result = [
208 'status' => $this->status,
209 'inProgress' => $this->stage !== false,
210 ];
211
212 // Add on version status
213 if ( $this->status === self::STATUS_NEED_INSTALL || $this->status === self::STATUS_NEED_UPDATING ) {
214 $result = array_merge( $result, $this->get_version_upgrade() );
215 }
216
217 if ( $this->status == self::STATUS_NEED_INSTALL ) {
218 $result['api'] = [
219 REDIRECTION_API_JSON => red_get_rest_api( REDIRECTION_API_JSON ),
220 REDIRECTION_API_JSON_INDEX => red_get_rest_api( REDIRECTION_API_JSON_INDEX ),
221 REDIRECTION_API_JSON_RELATIVE => red_get_rest_api( REDIRECTION_API_JSON_RELATIVE ),
222 ];
223 }
224
225 // Add on upgrade status
226 if ( $this->is_error() ) {
227 $result = array_merge( $result, $this->get_version_upgrade(), $this->get_progress_status(), $this->get_error_status() );
228 } elseif ( $result['inProgress'] ) {
229 $result = array_merge( $result, $this->get_progress_status() );
230 } elseif ( $this->status === self::STATUS_FINISHED_INSTALL || $this->status === self::STATUS_FINISHED_UPDATING ) {
231 $result['complete'] = 100;
232 $result['reason'] = $this->reason;
233 }
234
235 return $result;
236 }
237
238 private function get_error_status() {
239 return [
240 'reason' => $this->reason,
241 'result' => self::RESULT_ERROR,
242 'debug' => $this->debug,
243 ];
244 }
245
246 private function get_progress_status() {
247 $complete = 0;
248
249 if ( $this->stage ) {
250 $complete = round( ( array_search( $this->stage, $this->stages, true ) / count( $this->stages ) ) * 100, 1 );
251 }
252
253 return [
254 'complete' => $complete,
255 'result' => self::RESULT_OK,
256 'reason' => $this->reason,
257 ];
258 }
259
260 private function get_version_upgrade() {
261 return [
262 'current' => $this->get_current_version() ? $this->get_current_version() : '-',
263 'next' => REDIRECTION_DB_VERSION,
264 'time' => microtime( true ),
265 ];
266 }
267
268 /**
269 * Set the status information for a database upgrade
270 */
271 public function start_install( array $upgrades ) {
272 $this->set_stages( $upgrades );
273 $this->status = self::STATUS_NEED_INSTALL;
274 }
275
276 public function start_upgrade( array $upgrades ) {
277 $this->set_stages( $upgrades );
278 $this->status = self::STATUS_NEED_UPDATING;
279 }
280
281 private function set_stages( array $upgrades ) {
282 $this->stages = [];
283
284 foreach ( $upgrades as $upgrade ) {
285 $upgrader = Red_Database_Upgrader::get( $upgrade );
286 $this->stages = array_merge( $this->stages, array_keys( $upgrader->get_stages() ) );
287 }
288
289 if ( count( $this->stages ) > 0 ) {
290 $this->set_stage( $this->stages[0] );
291 }
292 }
293
294 public function set_stage( $stage ) {
295 $this->stage = $stage;
296 $this->save_details();
297 }
298
299 private function save_details() {
300 update_option( self::DB_UPGRADE_STAGE, [
301 'stage' => $this->stage,
302 'stages' => $this->stages,
303 'status' => $this->status,
304 ] );
305 }
306
307 private function get_next_stage( $stage ) {
308 $database = new Red_Database();
309 $upgraders = $database->get_upgrades_for_version( $this->get_current_version(), $this->get_current_stage() );
310
311 if ( count( $upgraders ) === 0 ) {
312 $upgraders = $database->get_upgrades_for_version( $this->get_current_version(), false );
313 }
314
315 $upgrader = Red_Database_Upgrader::get( $upgraders[0] );
316
317 // Where are we in this?
318 $pos = array_search( $this->stage, $this->stages, true );
319
320 if ( $pos === count( $this->stages ) - 1 ) {
321 $this->save_db_version( REDIRECTION_DB_VERSION );
322 return false;
323 }
324
325 // Set current DB version
326 $current_stages = array_keys( $upgrader->get_stages() );
327
328 if ( array_search( $this->stage, $current_stages, true ) === count( $current_stages ) - 1 ) {
329 $this->save_db_version( $upgraders[1]['version'] );
330 }
331
332 // Move on to next in current version
333 return $this->stages[ $pos + 1 ];
334 }
335
336 private function save_db_version( $version ) {
337 red_set_options( array( 'database' => $version ) );
338 delete_option( self::OLD_DB_VERSION );
339 }
340 }
341