Completed
Push — master ( 9e736e...81fa44 )
by Stephanie
02:35
created

FrmMigrate::upgrade()   B

Complexity

Conditions 6
Paths 12

Size

Total Lines 39
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 20
nc 12
nop 1
dl 0
loc 39
rs 8.439
c 0
b 0
f 0
1
<?php
2
3
class FrmMigrate {
4
	public $fields;
5
	public $forms;
6
	public $entries;
7
	public $entry_metas;
8
9 View Code Duplication
	public function __construct() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
10
		if ( ! defined('ABSPATH') ) {
11
			die('You are not allowed to call this page directly.');
12
		}
13
14
		global $wpdb;
15
		$this->fields         = $wpdb->prefix . 'frm_fields';
16
		$this->forms          = $wpdb->prefix . 'frm_forms';
17
		$this->entries        = $wpdb->prefix . 'frm_items';
18
		$this->entry_metas    = $wpdb->prefix . 'frm_item_metas';
19
	}
20
21
	public function upgrade( $old_db_version = false ) {
22
		do_action( 'frm_before_install' );
23
24
		global $wpdb;
25
		//$frm_db_version is the version of the database we're moving to
26
		$frm_db_version = FrmAppHelper::$db_version;
27
		$old_db_version = (float) $old_db_version;
28
		if ( ! $old_db_version ) {
29
			$old_db_version = get_option('frm_db_version');
30
		}
31
32
		if ( $frm_db_version != $old_db_version ) {
33
			// update rewrite rules for views and other custom post types
34
			flush_rewrite_rules();
35
36
			require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
37
38
			$this->create_tables();
39
			$this->migrate_data($frm_db_version, $old_db_version);
40
41
			/***** SAVE DB VERSION *****/
42
			update_option('frm_db_version', $frm_db_version);
43
44
			/**** ADD/UPDATE DEFAULT TEMPLATES ****/
45
			FrmXMLController::add_default_templates();
46
47
			if ( ! $old_db_version ) {
48
				$this->maybe_create_contact_form();
49
			}
50
		}
51
52
		do_action('frm_after_install');
53
54
		/**** update the styling settings ****/
55
		if ( is_admin() && function_exists( 'get_filesystem_method' ) ) {
56
			$frm_style = new FrmStyle();
57
			$frm_style->update( 'default' );
58
		}
59
	}
60
61
	public function collation() {
62
		global $wpdb;
63
		if ( ! $wpdb->has_cap( 'collation' ) ) {
64
			return '';
65
		}
66
67
		$charset_collate = '';
68
		if ( ! empty( $wpdb->charset ) ) {
69
			$charset_collate .= ' DEFAULT CHARACTER SET ' . $wpdb->charset;
70
		}
71
72
		if ( ! empty( $wpdb->collate ) ) {
73
			$charset_collate .= ' COLLATE ' . $wpdb->collate;
74
		}
75
76
		return $charset_collate;
77
	}
78
79
    private function create_tables() {
80
        $charset_collate = $this->collation();
81
        $sql = array();
82
83
        /* Create/Upgrade Fields Table */
84
		$sql[] = 'CREATE TABLE ' . $this->fields . ' (
85
				id BIGINT(20) NOT NULL auto_increment,
86
				field_key varchar(100) default NULL,
87
                name text default NULL,
88
                description longtext default NULL,
89
                type text default NULL,
90
                default_value longtext default NULL,
91
                options longtext default NULL,
92
                field_order int(11) default 0,
93
                required int(1) default NULL,
94
                field_options longtext default NULL,
95
                form_id int(11) default NULL,
96
                created_at datetime NOT NULL,
97
                PRIMARY KEY  (id),
98
                KEY form_id (form_id),
99
                UNIQUE KEY field_key (field_key)
100
        )';
101
102
        /* Create/Upgrade Forms Table */
103
		$sql[] = 'CREATE TABLE ' . $this->forms . ' (
104
                id int(11) NOT NULL auto_increment,
105
				form_key varchar(100) default NULL,
106
                name varchar(255) default NULL,
107
                description text default NULL,
108
                parent_form_id int(11) default 0,
109
                logged_in tinyint(1) default NULL,
110
                editable tinyint(1) default NULL,
111
                is_template tinyint(1) default 0,
112
                default_template tinyint(1) default 0,
113
                status varchar(255) default NULL,
114
                options longtext default NULL,
115
                created_at datetime NOT NULL,
116
                PRIMARY KEY  (id),
117
                UNIQUE KEY form_key (form_key)
118
        )';
119
120
        /* Create/Upgrade Items Table */
121
		$sql[] = 'CREATE TABLE ' . $this->entries . ' (
122
				id BIGINT(20) NOT NULL auto_increment,
123
				item_key varchar(100) default NULL,
124
                name varchar(255) default NULL,
125
                description text default NULL,
126
                ip text default NULL,
127
				form_id BIGINT(20) default NULL,
128
				post_id BIGINT(20) default NULL,
129
				user_id BIGINT(20) default NULL,
130
				parent_item_id BIGINT(20) default 0,
131
				is_draft tinyint(1) default 0,
132
				updated_by BIGINT(20) default NULL,
133
                created_at datetime NOT NULL,
134
                updated_at datetime NOT NULL,
135
                PRIMARY KEY  (id),
136
                KEY form_id (form_id),
137
                KEY post_id (post_id),
138
                KEY user_id (user_id),
139
                KEY parent_item_id (parent_item_id),
140
                UNIQUE KEY item_key (item_key)
141
        )';
142
143
        /* Create/Upgrade Meta Table */
144
		$sql[] = 'CREATE TABLE ' . $this->entry_metas . ' (
145
				id BIGINT(20) NOT NULL auto_increment,
146
				meta_value longtext default NULL,
147
				field_id BIGINT(20) NOT NULL,
148
				item_id BIGINT(20) NOT NULL,
149
                created_at datetime NOT NULL,
150
                PRIMARY KEY  (id),
151
                KEY field_id (field_id),
152
                KEY item_id (item_id)
153
        )';
154
155
        foreach ( $sql as $q ) {
156
			if ( function_exists( 'dbDelta' ) ) {
157
				dbDelta( $q . $charset_collate . ';' );
158
			} else {
159
				global $wpdb;
160
				$wpdb->query( $q . $charset_collate );
161
			}
162
            unset($q);
163
        }
164
    }
165
166
	private function maybe_create_contact_form() {
167
		$template_id = FrmForm::getIdByKey( 'contact' );
168
		if ( $template_id ) {
169
			$form_id = FrmForm::duplicate( $template_id, false, true );
170
			if ( $form_id ) {
171
				$values = array(
172
					'status'   => 'published',
173
					'form_key' => 'contact-form',
174
				);
175
				FrmForm::update( $form_id, $values );
176
			}
177
		}
178
	}
179
180
    /**
181
     * @param integer $frm_db_version
182
	 * @param int $old_db_version
183
     */
184
	private function migrate_data( $frm_db_version, $old_db_version ) {
185
		$migrations = array( 4, 6, 11, 16, 17, 23, 25 );
186
        foreach ( $migrations as $migration ) {
187
            if ( $frm_db_version >= $migration && $old_db_version < $migration ) {
188
				$function_name = 'migrate_to_' . $migration;
189
                $this->$function_name();
190
            }
191
        }
192
    }
193
194
    public function uninstall() {
195
		if ( ! current_user_can( 'administrator' ) ) {
196
            $frm_settings = FrmAppHelper::get_settings();
197
            wp_die($frm_settings->admin_permission);
198
        }
199
200
        global $wpdb, $wp_roles;
201
202
		$wpdb->query( 'DROP TABLE IF EXISTS ' . $this->fields );
203
		$wpdb->query( 'DROP TABLE IF EXISTS ' . $this->forms );
204
		$wpdb->query( 'DROP TABLE IF EXISTS ' . $this->entries );
205
		$wpdb->query( 'DROP TABLE IF EXISTS ' . $this->entry_metas );
206
207
        delete_option('frm_options');
208
        delete_option('frm_db_version');
209
210
        //delete roles
211
        $frm_roles = FrmAppHelper::frm_capabilities();
212
        $roles = get_editable_roles();
213
        foreach ( $frm_roles as $frm_role => $frm_role_description ) {
214
            foreach ( $roles as $role => $details ) {
215
                $wp_roles->remove_cap( $role, $frm_role );
216
                unset($role, $details);
217
    		}
218
    		unset($frm_role, $frm_role_description);
219
		}
220
		unset($roles, $frm_roles);
221
222
		// delete actions, views, and styles
223
224
		// prevent the post deletion from triggering entries to be deleted
225
		remove_action( 'before_delete_post', 'FrmProDisplaysController::before_delete_post' );
226
		remove_action( 'deleted_post', 'FrmProEntriesController::delete_entry' );
227
228
		$post_ids = $wpdb->get_col( $wpdb->prepare( 'SELECT ID FROM ' . $wpdb->posts . ' WHERE post_type in (%s, %s, %s)', FrmFormActionsController::$action_post_type, FrmStylesController::$post_type, 'frm_display' ) );
229
		foreach ( $post_ids as $post_id ) {
230
			// Delete's each post.
231
			wp_delete_post( $post_id, true );
232
		}
233
		unset( $post_ids );
234
235
		// delete transients
236
		delete_transient( 'frmpro_css' );
237
		delete_transient( 'frm_options' );
238
		delete_transient( 'frmpro_options' );
239
240
		$wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->options . ' WHERE option_name LIKE %s OR option_name LIKE %s', '_transient_timeout_frm_form_fields_%', '_transient_frm_form_fields_%' ) );
241
242
        do_action('frm_after_uninstall');
243
        return true;
244
    }
245
246
	/**
247
	 * Migrate old styling settings. If sites are using the old
248
	 * default 400px field width, switch it to 100%
249
	 *
250
	 * @since 2.0.4
251
	 */
252
	private function migrate_to_25() {
253
		// get the style that was created with the style migration
254
		$frm_style = new FrmStyle();
255
		$styles = $frm_style->get_all( 'post_date', 'ASC', 1 );
256
		if ( empty( $styles ) ) {
257
			return;
258
		}
259
260
		foreach ( $styles as $style ) {
261
			if ( $style->post_content['field_width'] == '400px' ) {
262
				$style->post_content['field_width'] = '100%';
263
				$frm_style->save( (array) $style );
264
				return;
265
			}
266
		}
267
	}
268
269
	/**
270
	 * Check if the parent_form_id columns exists.
271
	 * If not, try and add it again
272
	 *
273
	 * @since 2.0.2
274
	 */
275
	private function migrate_to_23() {
276
		global $wpdb;
277
		$exists = $wpdb->get_row( 'SHOW COLUMNS FROM ' . $this->forms . ' LIKE "parent_form_id"' );
278
		if ( empty( $exists ) ) {
279
			$wpdb->query( 'ALTER TABLE ' . $this->forms . ' ADD parent_form_id int(11) default 0' );
280
		}
281
	}
282
283
    /**
284
     * Change field size from character to pixel -- Multiply by 9
285
     */
286
    private function migrate_to_17() {
287
        global $wpdb;
288
		$pixel_conversion = 9;
289
290
        // Get query arguments
291
		$field_types = array( 'textarea', 'text', 'number', 'email', 'url', 'rte', 'date', 'phone', 'password', 'image', 'tag', 'file' );
292
		$query = array( 'type' => $field_types, 'field_options like' => 's:4:"size";', 'field_options not like' => 's:4:"size";s:0:' );
293
294
        // Get results
295
		$fields = FrmDb::get_results( $this->fields, $query, 'id, field_options' );
296
297
        $updated = 0;
298
        foreach ( $fields as $f ) {
0 ignored issues
show
Bug introduced by
The expression $fields of type array|null|string|object is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
299
            $f->field_options = maybe_unserialize($f->field_options);
300
            if ( empty($f->field_options['size']) || ! is_numeric($f->field_options['size']) ) {
301
                continue;
302
            }
303
304
			$f->field_options['size'] = round( $pixel_conversion * (int) $f->field_options['size'] );
305
            $f->field_options['size'] .= 'px';
306
            $u = FrmField::update( $f->id, array( 'field_options' => $f->field_options ) );
307
            if ( $u ) {
308
                $updated++;
309
            }
310
            unset($f);
311
        }
312
313
        // Change the characters in widgets to pixels
314
        $widgets = get_option('widget_frm_show_form');
315
        if ( empty($widgets) ) {
316
            return;
317
        }
318
319
        $widgets = maybe_unserialize($widgets);
320
        foreach ( $widgets as $k => $widget ) {
321
            if ( ! is_array($widget) || ! isset($widget['size']) ) {
322
                continue;
323
            }
324
			$size = round( $pixel_conversion * (int) $widget['size'] );
325
            $size .= 'px';
326
			$widgets[ $k ]['size'] = $size;
327
        }
328
        update_option('widget_frm_show_form', $widgets);
329
    }
330
331
    /**
332
     * Migrate post and email notification settings into actions
333
     */
334
    private function migrate_to_16() {
335
        global $wpdb;
336
337
        $forms = FrmDb::get_results( $this->forms, array(), 'id, options, is_template, default_template' );
338
339
        /**
340
        * Old email settings format:
341
        * email_to: Email or field id
342
        * also_email_to: array of fields ids
343
        * reply_to: Email, field id, 'custom'
344
        * cust_reply_to: string
345
        * reply_to_name: field id, 'custom'
346
        * cust_reply_to_name: string
347
        * plain_text: 0|1
348
        * email_message: string or ''
349
        * email_subject: string or ''
350
        * inc_user_info: 0|1
351
        * update_email: 0, 1, 2
352
        *
353
        * Old autoresponder settings format:
354
        * auto_responder: 0|1
355
        * ar_email_message: string or ''
356
        * ar_email_to: field id
357
        * ar_plain_text: 0|1
358
        * ar_reply_to_name: string
359
        * ar_reply_to: string
360
        * ar_email_subject: string
361
        * ar_update_email: 0, 1, 2
362
        *
363
        * New email settings:
364
        * post_content: json settings
365
        * post_title: form id
366
        * post_excerpt: message
367
        *
368
        */
369
370
        foreach ( $forms as $form ) {
0 ignored issues
show
Bug introduced by
The expression $forms of type array|null|string|object is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
371
			if ( $form->is_template && $form->default_template ) {
372
				// don't migrate the default templates since the email will be added anyway
373
				continue;
374
			}
375
376
            // Format form options
377
            $form_options = maybe_unserialize($form->options);
378
379
            // Migrate settings to actions
380
            FrmXMLHelper::migrate_form_settings_to_actions( $form_options, $form->id );
381
        }
382
    }
383
384
    private function migrate_to_11() {
385
        global $wpdb;
386
387
        $forms = FrmDb::get_results( $this->forms, array(), 'id, options');
388
389
        $sending = __( 'Sending', 'formidable' );
390
		$img = FrmAppHelper::plugin_url() . '/images/ajax_loader.gif';
391
        $old_default_html = <<<DEFAULT_HTML
392
<div class="frm_submit">
393
[if back_button]<input type="submit" value="[back_label]" name="frm_prev_page" formnovalidate="formnovalidate" [back_hook] />[/if back_button]
394
<input type="submit" value="[button_label]" [button_action] />
395
<img class="frm_ajax_loading" src="$img" alt="$sending" style="visibility:hidden;" />
396
</div>
397
DEFAULT_HTML;
398
        unset($sending, $img);
399
400
        $new_default_html = FrmFormsHelper::get_default_html('submit');
401
        $draft_link = FrmFormsHelper::get_draft_link();
402
		foreach ( $forms as $form ) {
0 ignored issues
show
Bug introduced by
The expression $forms of type array|null|string|object is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
403
            $form->options = maybe_unserialize($form->options);
404
            if ( ! isset($form->options['submit_html']) || empty($form->options['submit_html']) ) {
405
                continue;
406
            }
407
408
            if ( $form->options['submit_html'] != $new_default_html && $form->options['submit_html'] == $old_default_html ) {
409
                $form->options['submit_html'] = $new_default_html;
410
				$wpdb->update( $this->forms, array( 'options' => serialize( $form->options ) ), array( 'id' => $form->id ) );
411
			} else if ( ! strpos( $form->options['submit_html'], 'save_draft' ) ) {
412
				$form->options['submit_html'] = preg_replace( '~\<\/div\>(?!.*\<\/div\>)~', $draft_link . "\r\n</div>", $form->options['submit_html'] );
413
				$wpdb->update( $this->forms, array( 'options' => serialize( $form->options ) ), array( 'id' => $form->id ) );
414
            }
415
            unset($form);
416
        }
417
        unset($forms);
418
    }
419
420
    private function migrate_to_6() {
421
        global $wpdb;
422
423
		$no_save = array_merge( FrmField::no_save_fields(), array( 'form', 'hidden', 'user_id' ) );
424
		$fields = FrmDb::get_results( $this->fields, array( 'type NOT' => $no_save ), 'id, field_options' );
425
426
        $default_html = <<<DEFAULT_HTML
427
<div id="frm_field_[id]_container" class="form-field [required_class] [error_class]">
428
    <label class="frm_pos_[label_position]">[field_name]
429
        <span class="frm_required">[required_label]</span>
430
    </label>
431
    [input]
432
    [if description]<div class="frm_description">[description]</div>[/if description]
433
</div>
434
DEFAULT_HTML;
435
436
        $old_default_html = <<<DEFAULT_HTML
437
<div id="frm_field_[id]_container" class="form-field [required_class] [error_class]">
438
    <label class="frm_pos_[label_position]">[field_name]
439
        <span class="frm_required">[required_label]</span>
440
    </label>
441
    [input]
442
    [if description]<p class="frm_description">[description]</p>[/if description]
443
</div>
444
DEFAULT_HTML;
445
446
        $new_default_html = FrmFieldsHelper::get_default_html('text');
447
        foreach ( $fields as $field ) {
0 ignored issues
show
Bug introduced by
The expression $fields of type array|null|string|object is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
448
            $field->field_options = maybe_unserialize($field->field_options);
449
			$html = FrmField::get_option( $field, 'custom_html' );
450
			if ( $html == $default_html || $html == $old_default_html ) {
451
                $field->field_options['custom_html'] = $new_default_html;
452
				$wpdb->update( $this->fields, array( 'field_options' => maybe_serialize( $field->field_options ) ), array( 'id' => $field->id ) );
453
            }
454
            unset($field);
455
        }
456
        unset($default_html, $old_default_html, $fields);
457
    }
458
459
    private function migrate_to_4() {
460
        global $wpdb;
461
		$user_ids = FrmEntryMeta::getAll( array( 'fi.type' => 'user_id' ) );
462
        foreach ( $user_ids as $user_id ) {
463
			$wpdb->update( $this->entries, array( 'user_id' => $user_id->meta_value ), array( 'id' => $user_id->item_id ) );
464
        }
465
    }
466
}
467