Completed
Push — master ( 223941...33757f )
by Stephanie
02:50
created

FrmFormMigrator   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 386
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
dl 0
loc 386
rs 8.8798
c 0
b 0
f 0
wmc 44
lcom 1
cbo 5

25 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 18 3
A maybe_add_to_import_page() 0 5 1
A import_page() 0 48 3
A import_forms() 0 24 3
A import_form() 0 23 2
A prepare_new_form() 0 10 1
A prepare_form() 0 3 1
A prepare_fields() 0 28 4
A prepare_field() 0 3 1
A convert_field_type() 0 3 1
B add_form() 0 52 6
A track_import() 0 8 1
A get_tracked_import() 0 3 1
A is_imported() 0 8 3
A unsupported_field_types() 0 3 1
A is_unsupported_field() 0 4 1
A skip_pro_fields() 0 3 1
A should_skip_field() 0 4 2
A replace_smart_tags() 0 3 1
A get_forms() 0 3 1
A get_form() 0 3 1
A get_form_name() 0 3 1
A get_form_fields() 0 3 1
A get_field_type() 0 3 2
A get_field_label() 0 10 1

How to fix   Complexity   

Complex Class

Complex classes like FrmFormMigrator often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use FrmFormMigrator, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
abstract class FrmFormMigrator {
4
5
	public $source_active;
6
7
	public $slug;
8
	public $path;
9
	public $name;
10
11
	public $response = array();
12
	public $tracking = 'frm_forms_imported';
13
14
	/**
15
	 * Define required properties.
16
	 */
17
	public function __construct() {
18
		if ( ! is_admin() ) {
19
			return;
20
		}
21
22
		$this->source_active = is_plugin_active( $this->path );
23
		if ( ! $this->source_active ) {
24
			// if source plugin is not installed, do nothing
25
			return;
26
		}
27
		
28
		$this->maybe_add_to_import_page();
29
30
		$this->response = array(
31
			'upgrade_omit' => array(),
32
			'unsupported'  => array(),
33
		);
34
	}
35
36
	private function maybe_add_to_import_page() {
37
		$menu_name = sanitize_title( FrmAppHelper::get_menu_name() );
38
		add_action( $menu_name . '_page_formidable-import', array( $this, 'import_page' ), 1 );
39
		add_action( 'wp_ajax_frm_import_' . $this->slug, array( $this, 'import_forms' ) );
40
	}
41
42
	public function import_page() {
43
		?>
44
		<div class="wrap">
45
			<div class="welcome-panel" id="welcome-panel">
46
				<h2><?php echo esc_html( $this->name ); ?> Importer</h2>
47
				<div class="welcome-panel-content" style="text-align:center;margin-bottom:10px;">
48
					<p class="about-description">
49
						Import forms and settings automatically from <?php echo esc_html( $this->name ); ?>. <br/>
50
						Select the forms to import.
51
					</p>
52
					<form id="frm_form_importer" method="post" action="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>">
53
						<?php wp_nonce_field( 'nonce', 'frm_ajax' ); ?>
54
						<input type="hidden" name="slug" value="<?php echo esc_attr( $this->slug ); ?>" />
55
						<input type="hidden" name="action" value="frm_import_<?php echo esc_attr( $this->slug ); ?>" />
56
						<div style="margin:10px auto;max-width:400px;">
57
							<?php foreach ( $this->get_forms() as $form_id => $name ) { ?>
58
								<p>
59
									<label>
60
										<input type="checkbox" name="form_id[]" value="<?php echo esc_attr( $form_id ); ?>" checked="checked" />
61
										<?php echo esc_html( $name ); ?>
62
										<?php if ( $new_form_id = $this->is_imported( $form_id ) ) { ?>
63
											(<a href="<?php echo esc_url( admin_url( 'admin.php?page=formidable&frm_action=edit&id=' . $new_form_id ) ); ?>">previously imported</a>)
64
										<?php } ?>
65
									</label>
66
								</p>
67
							<?php } ?>
68
						</div>
69
						<button type="submit" class="button button-primary button-hero">Start Import</button>
70
					</form>
71
					<div id="frm-importer-process" class="frm_hidden">
72
73
						<p class="process-count">
74
							<i class="fa fa-spinner fa-spin" aria-hidden="true"></i>
75
							Importing <span class="form-current">1</span> of <span class="form-total">0</span> forms from <?php echo esc_html( $this->name ); ?>.
76
						</p>
77
78
						<p class="process-completed" class="frm_hidden">
79
							The import process has finished! We have successfully imported <span class="forms-completed"></span> forms. You can review the results below.
80
						</p>
81
82
						<div class="status"></div>
83
84
					</div>
85
				</div>
86
			</div>
87
		</div>
88
		<?php
89
	}
90
91
	/**
92
	 * Import all forms using ajax
93
	 */
94
	public function import_forms() {
95
96
		check_ajax_referer( 'frm_ajax', 'nonce' );
97
		FrmAppHelper::permission_check( 'frm_edit_forms' );
98
99
		$forms = FrmAppHelper::get_simple_request(
100
			array(
101
				'param'    => 'form_id',
102
				'type'     => 'post',
103
				'sanitize' => 'absint',
104
			)
105
		);
106
107
		if ( is_array( $forms ) ) {
108
			$imported = array();
109
			foreach ( (array) $forms as $form_id ) {
110
				$imported[] = $this->import_form( $form_id );
111
			}
112
		} else {
113
			$imported = $this->import_form( $forms );
114
		}
115
116
		wp_send_json_success( $imported );
117
	}
118
119
	/**
120
	 * Import a single form
121
	 */
122
	protected function import_form( $source_id ) {
123
124
		$source_form        = $this->get_form( $source_id );
125
		$source_form_name   = $this->get_form_name( $source_form );
126
		$source_fields      = $this->get_form_fields( $source_form );
127
128
		// If form does not contain fields, bail.
129
		if ( empty( $source_fields ) ) {
130
			wp_send_json_success( array(
131
				'error' => true,
132
				'name'  => esc_html( $source_form_name ),
133
				'msg'   => __( 'No form fields found.', 'formidable' ),
134
			) );
135
		}
136
137
		$form = $this->prepare_new_form( $source_id, $source_form_name );
138
139
		$this->prepare_fields( $source_fields, $form );
140
141
		$this->prepare_form( $source_form, $form );
142
143
		return $this->add_form( $form );
144
	}
145
146
	protected function prepare_new_form( $source_id, $source_form_name ) {
147
		return array(
148
			'import_form_id' => $source_id,
149
			'fields'         => array(),
150
			'name'           => $source_form_name,
151
			'description'    => '',
152
			'options'        => array(),
153
			'actions'        => array(),
154
		);
155
	}
156
157
	protected function prepare_form( $form, &$new_form ) {
158
		// customize this function
159
	}
160
161
	protected function prepare_fields( $fields, &$form ) {
162
163
		foreach ( $fields as $field ) {
164
165
			$label = $this->get_field_label( $field );
166
			$type  = $this->get_field_type( $field );
167
168
			// check if field is unsupported. If unsupported make note and continue
169
			if ( $this->is_unsupported_field( $type ) ) {
170
				$this->response['unsupported'][] = $label;
171
				continue;
172
			}
173
			
174
			if ( $this->should_skip_field( $type ) ) {
175
				$this->response['upgrade_omit'][] = $label;
176
				continue;
177
			}
178
179
			$new_field = array(
180
				'type'     => $this->convert_field_type( $type ),
181
				'name'     => $label,
182
				'original' => $type,
183
			);
184
185
			$this->prepare_field( $field, $new_field );
186
			$form['fields'][] = $new_field;
187
		}
188
	}
189
190
	protected function prepare_field( $field, &$new_field ) {
191
		// customize this function
192
	}
193
194
	protected function convert_field_type( $type ) {
195
		return $type;
196
	}
197
198
	/**
199
	 * Add the new form to the database and return AJAX data.
200
	 *
201
	 * @since 1.4.2
202
	 *
203
	 * @param array $form Form to import.
204
	 * @param array $upgrade_omit No field alternative
205
	 */
206
	private function add_form( $form, $upgrade_omit = array() ) {
207
208
		// Create empty form so we have an ID to work with.
209
		$form_id = FrmForm::create(
210
			array(
211
				'name'        => $form['name'],
212
				'description' => $form['description'],
213
				'options'     => $form['options'],
214
			)
215
		);
216
217
		if ( empty( $form_id ) ) {
218
			return array(
219
				'error' => true,
220
				'name'  => sanitize_text_field( $form['settings']['form_title'] ),
221
				'msg'   => esc_html__( 'There was an error while creating a new form.', 'formidable' ),
222
			);
223
		}
224
225
		foreach ( $form['fields'] as $key => $field ) {
226
			$new_field = FrmFieldsHelper::setup_new_vars( $field['type'], $form_id );
227
			$new_field = array_merge( $new_field, $field );
228
			$new_field['field_options'] = array_merge( $new_field['field_options'], $field );
229
			$form['fields'][ $key ]['id'] = FrmField::create( $new_field, $form_id );
0 ignored issues
show
Bug introduced by
It seems like $form_id defined by \FrmForm::create(array('...' => $form['options'])) on line 209 can also be of type integer; however, FrmField::create() does only seem to accept boolean, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
230
		}
231
232
		// create emails
233
		foreach ( $form['actions'] as $action ) {
234
			$action_control = FrmFormActionsController::get_form_actions( $action['type'] );
235
			unset( $action['type'] );
236
			$new_action = $action_control->prepare_new( $form_id );
237
			foreach ( $action as $key => $value ) {
238
				if ( $key === 'post_title' ) {
239
					$new_action->post_title = $value;
240
				} else {
241
					$new_action->post_content[ $key ] = $this->replace_smart_tags( $value, $form['fields'] );
242
				}
243
			}
244
245
			$action_control->save_settings( $new_action );
246
		}
247
248
		$this->track_import( $form['import_form_id'], $form_id );
0 ignored issues
show
Bug introduced by
It seems like $form_id defined by \FrmForm::create(array('...' => $form['options'])) on line 209 can also be of type boolean; however, FrmFormMigrator::track_import() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
249
250
		// Build and send final AJAX response!
251
		return array(
252
			'name'          => $form['name'],
253
			'id'            => $form_id,
254
			'link'          => esc_url_raw( admin_url( 'admin.php?page=formidable&frm_action=edit&id=' . $form_id ) ),
255
			'upgrade_omit'  => $this->response['upgrade_omit'],
256
		);
257
	}
258
259
	/**
260
	 * After a form has been successfully imported we track it, so that in the
261
	 * future we can alert users if they try to import a form that has already
262
	 * been imported.
263
	 *
264
	 * @param int $source_id Imported plugin form ID
265
	 * @param int $new_form_id Formidable form ID
266
	 */
267
	private function track_import( $source_id, $new_form_id ) {
268
269
		$imported = $this->get_tracked_import();
270
271
		$imported[ $this->slug ][ $new_form_id ] = $source_id;
272
273
		update_option( $this->tracking, $imported, false );
274
	}
275
276
	/**
277
	 * @return array
278
	 */
279
	private function get_tracked_import() {
280
		return get_option( $this->tracking, array() );
281
	}
282
283
	/**
284
	 * @param int $source_id Imported plugin form ID
285
	 *
286
	 * @return int the ID of the created form or 0
287
	 */
288
	private function is_imported( $source_id ) {
289
		$imported = $this->get_tracked_import();
290
		$new_form_id = 0;
291
		if ( isset( $imported[ $this->slug ] ) && in_array( $source_id, $imported[ $this->slug ] ) ) {
292
			$new_form_id = array_search( $source_id, array_reverse( $imported[ $this->slug ], true ) );
293
		}
294
		return $new_form_id;
295
	}
296
297
	/** Start functions here that should be overridden **/
298
299
	/**
300
	 * @return array
301
	 */
302
	protected function unsupported_field_types() {
303
		return array();
304
	}
305
306
	private function is_unsupported_field( $type ) {
307
		$fields = $this->unsupported_field_types(); 
308
		return in_array( $type, $fields, true );
309
	}
310
311
	/**
312
	 * Strict PRO fields with no Lite alternatives.
313
	 * @return array
314
	 */
315
	protected function skip_pro_fields() {
316
		return array();
317
	}
318
319
	private function should_skip_field( $type ) {
320
		$skip_pro_fields = $this->skip_pro_fields(); 
321
		return ( ! FrmAppHelper::pro_is_installed() && in_array( $type, $skip_pro_fields, true ) );
322
	}
323
324
	/**
325
	 * Replace 3rd-party form provider tags/shortcodes with our own Tags.
326
	 *
327
	 * @param string $string String to process the smart tag in.
328
	 * @param array  $fields List of fields for the form.
329
	 *
330
	 * @return string
331
	 */
332
	protected function replace_smart_tags( $string, $fields ) {
333
		return $string;
334
	}
335
336
	/**
337
	 * Get ALL THE FORMS.
338
	 *
339
	 * @return array
340
	 */
341
	public function get_forms() {
342
		return array();
343
	}
344
345
	public function get_form( $id ) {
346
		return array();
347
	}
348
349
	/**
350
	 * @param object|array $source_form
351
	 * @return string
352
	 */
353
	protected function get_form_name( $source_form ) {
354
		return __( 'Default Form', 'formidable' );
355
	}
356
357
	/**
358
	 * @param object|array $source_form
359
	 * @return array
360
	 */
361
	protected function get_form_fields( $source_form ) {
362
		return array();
363
	}
364
365
	/**
366
	 * @param object|array $field
367
	 * @return string
368
	 */
369
	protected function get_field_type( $field ) {
370
		return is_array( $field ) ? $field['type'] : $field->type;
371
	}
372
373
	/**
374
	 * @param object|array $field
375
	 *
376
	 * @return string
377
	 */
378
	public function get_field_label( $field ) {
379
		$type = $this->get_field_type( $field );
380
		$label = sprintf(
381
			/* translators: %1$s - field type */
382
			esc_html__( '%1$s Field', 'formidable' ),
383
			ucfirst( $type )
384
		);
385
386
		return trim( $label );
387
	}
388
}
389