Passed
Push — master ( c00ab5...5ed1e2 )
by litefeel
03:01
created

Writing_On_GitHub_Import   D

Complexity

Total Complexity 58

Size/Duplication

Total Lines 328
Duplicated Lines 11.59 %

Coupling/Cohesion

Dependencies 9

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 58
cbo 9
dl 38
loc 328
ccs 0
cts 155
cp 0
rs 4.8387
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A payload() 19 19 4
A importable_raw_file() 0 12 3
B import_files() 0 23 5
D compare() 0 73 18
A importable_file() 0 16 4
A importable_blob() 0 19 2
A import_raw_file() 0 16 4
C blob_to_post() 0 54 13
A master() 19 19 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Writing_On_GitHub_Import 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.

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 Writing_On_GitHub_Import, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * GitHub Import Manager
4
 *
5
 * @package Writing_On_GitHub
6
 */
7
8
/**
9
 * Class Writing_On_GitHub_Import
10
 */
11
class Writing_On_GitHub_Import {
12
13
	/**
14
	 * Application container.
15
	 *
16
	 * @var Writing_On_GitHub
17
	 */
18
	protected $app;
19
20
	/**
21
	 * Initializes a new import manager.
22
	 *
23
	 * @param Writing_On_GitHub $app Application container.
24
	 */
25
	public function __construct( Writing_On_GitHub $app ) {
26
		$this->app = $app;
27
	}
28
29
    /**
30
     * Imports a payload.
31
     * @param  Writing_On_GitHub_Payload $payload
32
     *
33
     * @return string|WP_Error
34
     */
35 View Code Duplication
	public function payload( Writing_On_GitHub_Payload $payload ) {
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...
36
37
		$result = $this->app->api()->fetch()->compare( $payload->get_before_commit_id() );
38
39
		if ( is_wp_error( $result ) ) {
40
            /* @var WP_Error $result */
41
			return $result;
42
		}
43
44
        if ( is_array( $result ) ) {
45
            $result = $this->import_files( $result );
46
        }
47
48
		if ( is_wp_error( $result ) ) {
49
			return $files;
50
		}
51
52
		return __( 'Payload processed', 'writing-on-github' );
53
	}
54
55
	/**
56
	 * import blob by files
57
	 * @param  Writing_On_GitHub_File_Info[] $files
58
     *
59
	 * @return string|WP_Error
0 ignored issues
show
Documentation introduced by
Should the return type not be WP_Error|string|array|false? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
60
	 */
61
	protected function import_files( $files ) {
62
63
		$error 		= false;
64
		$delete_ids = false;
65
66
		$result = $this->compare( $files, $delete_ids );
67
68
		if ( is_wp_error( $result ) ) {
69
			return $result;
70
		}
71
72
		if ( $delete_ids ) {
73
			foreach ($delete_ids as $id) {
0 ignored issues
show
introduced by
No space after opening parenthesis is prohibited
Loading history...
introduced by
No space before closing parenthesis is prohibited
Loading history...
74
				$result = $this->app->database()->delete_post( $id );
75
				if ( is_wp_error( $result ) ) {
76
                    /* @var WP_Error $result */
77
                    $error = wogh_append_error( $error, $result );
78
				}
79
			}
80
		}
81
82
		return $error;
83
	}
84
85
	/**
86
	 * Imports the latest commit on the master branch.
87
	 *
88
	 * @return string|WP_Error
89
	 */
90 View Code Duplication
	public function master() {
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...
91
		$result = $this->app->api()->fetch()->tree_recursive();
92
93
		if ( is_wp_error( $result ) ) {
94
            /* @var WP_Error $result */
95
			return $result;
96
		}
97
98
        if ( is_array( $result ) ) {
99
            $result = $this->import_files( $result );
100
        }
101
102
		if ( is_wp_error( $result ) ) {
103
            /* @var WP_Error $result */
104
			return $result;
105
		}
106
107
		return __( 'Payload processed', 'writing-on-github' );
108
	}
109
110
    /**
111
     * Do compare
112
     * @param  Writing_On_GitHub_File_Info[]|WP_Error $files
113
     * @param  int[] &$delete_ids
114
     *
115
     * @return string|WP_Error
0 ignored issues
show
Documentation introduced by
Should the return type not be WP_Error|string|array? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
116
     */
117
	protected function compare( $files, &$delete_ids ) {
0 ignored issues
show
Complexity introduced by
This operation has 7776 execution paths which exceeds the configured maximum of 200.

A high number of execution paths generally suggests many nested conditional statements and make the code less readible. This can usually be fixed by splitting the method into several smaller methods.

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

Loading history...
118
		if ( is_wp_error( $files ) ) {
119
            /* @var WP_Error $files */
120
			return $files;
121
		}
122
123
		$posts = array();
124
		$new   = array();
125
126
		$idsmap = array();
127
128
		foreach ( $files as $file ) {
129
			if ( ! $this->importable_file( $file ) ) {
130
				continue;
131
			}
132
133
			$blob = $this->app->api()->fetch()->blob( $file );
134
			// network error ?
135
			if ( ! $blob instanceof Writing_On_GitHub_Blob ) {
136
				continue;
137
			}
138
139
			if ( $this->importable_raw_file( $blob ) ) {
140
				$this->import_raw_file( $blob, $file->status == 'removed' );
141
				continue;
142
			}
143
144
			if ( ! $this->importable_blob( $blob ) ) {
145
				continue;
146
			}
147
148
			$post = $this->blob_to_post( $blob );
149
150
			if ( $file->status == 'removed' ) {
0 ignored issues
show
introduced by
Found "== '". Use Yoda Condition checks, you must
Loading history...
151
				if ( $blob->id() ) {
152
					$idsmap[$blob->id()] = true;
0 ignored issues
show
introduced by
Array keys should be surrounded by spaces unless they contain a string or an integer.
Loading history...
153
				}
154
			} elseif ( $post != false ) {
0 ignored issues
show
introduced by
Found "!= false". Use Yoda Condition checks, you must
Loading history...
155
				$posts[] = $post;
156
				if ( $post->is_new() ) {
157
					$new[] = $post;
158
				}
159
			}
160
		}
161
162
		foreach ( $posts as $post ) {
163
			if ( $post->id() && isset( $idsmap[ $post->id() ] ) ) {
164
				unset( $idsmap[ $post->id() ] );
165
			}
166
		}
167
		$delete_ids = array();
168
		foreach ( $idsmap as $id => $value ) {
169
			$delete_ids[] = $id;
170
		}
171
172
		// $this->app->database()->save_posts( $posts, $commit->author_email() );
173
174
		$result = $this->app->database()->save_posts( $posts );
175
176
		if ( is_wp_error( $result ) ) {
177
			return $result;
178
		}
179
180
		if ( ! empty( $new ) ) {
181
			$result = $this->app->export()->new_posts( $new );
182
183
			if ( is_wp_error( $result ) ) {
184
				return $result;
185
			}
186
		}
187
188
		return $posts;
189
	}
190
191
	/**
192
	 * Checks whether the provided blob should be imported.
193
	 *
194
	 * @param Writing_On_GitHub_File_Info $file
195
	 *
196
	 * @return bool
197
	 */
198
	protected function importable_file( Writing_On_GitHub_File_Info $file ) {
199
200
		// only _pages and _posts
201
		if ( strncasecmp($file->path, '_pages/', strlen('_pages/') ) != 0 &&
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return !(strncasecmp($fi...rlen('images/')) != 0);.
Loading history...
introduced by
Found "!= 0". Use Yoda Condition checks, you must
Loading history...
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
202
			 strncasecmp($file->path, '_posts/', strlen('_posts/') ) != 0 &&
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
203
			 strncasecmp($file->path, 'images/', strlen('images/') ) != 0 ) {
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
204
			return false;
205
		}
206
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
207
208
		// if ( ! $file->has_frontmatter() ) {
209
		// 	return false;
210
		// }
211
212
		return true;
213
	}
214
215
	/**
216
	 * Checks whether the provided blob should be imported.
217
	 *
218
	 * @param Writing_On_GitHub_Blob $blob Blob to validate.
219
	 *
220
	 * @return bool
221
	 */
222
	protected function importable_blob( Writing_On_GitHub_Blob $blob ) {
223
		// global $wpdb;
224
225
		// // Skip the repo's readme.
226
		// if ( 'readme' === strtolower( substr( $blob->path(), 0, 6 ) ) ) {
227
		// 	return false;
228
		// }
229
230
		// // If the blob sha already matches a post, then move on.
231
		// if ( ! is_wp_error( $this->app->database()->fetch_by_sha( $blob->sha() ) ) ) {
232
		// 	return false;
233
		// }
234
235
		if ( ! $blob->has_frontmatter() ) {
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return $blob->has_frontmatter();.
Loading history...
236
			return false;
237
		}
238
239
		return true;
240
	}
241
242
	protected function importable_raw_file( Writing_On_GitHub_Blob $blob ) {
243
		if ( $blob->has_frontmatter() ) {
244
			return false;
245
		}
246
247
		// only images
248
		if ( strncasecmp($blob->path(), 'images/', strlen('images/') ) != 0) {
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return !(strncasecmp($bl...rlen('images/')) != 0);.
Loading history...
introduced by
Found "!= 0". Use Yoda Condition checks, you must
Loading history...
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
introduced by
No space before closing parenthesis is prohibited
Loading history...
249
			return false;
250
		}
251
252
		return true;
253
	}
254
255
	/**
256
	 * Imports a raw file content into file system.
257
	 * @param  Writing_On_GitHub_Blob $blob
258
	 * @param  bool                   $is_remove
259
	 */
260
	protected function import_raw_file( Writing_On_GitHub_Blob $blob, $is_remove ) {
261
		$arr = wp_upload_dir();
262
		$path = $arr['basedir'] . '/writing-on-github/' . $blob->path();
263
		if ( $is_remove ) {
264
			if ( file_exists($path) ) {
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
265
				unlink($path);
0 ignored issues
show
introduced by
Filesystem writes are forbidden, you should not be using unlink()
Loading history...
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
266
			}
267
		} else {
268
			$dirname = dirname($path);
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
269
			if ( ! file_exists($dirname) ) {
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
270
				wp_mkdir_p($dirname);
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
271
			}
272
273
			file_put_contents($path, $blob->content());
0 ignored issues
show
introduced by
Filesystem writes are forbidden, you should not be using file_put_contents()
Loading history...
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
274
		}
275
	}
276
277
	/**
278
	 * Imports a single blob content into matching post.
279
	 *
280
	 * @param Writing_On_GitHub_Blob $blob Blob to transform into a Post.
281
	 *
282
	 * @return Writing_On_GitHub_Post|false
283
	 */
284
	protected function blob_to_post( Writing_On_GitHub_Blob $blob ) {
0 ignored issues
show
Complexity introduced by
This operation has 582 execution paths which exceeds the configured maximum of 200.

A high number of execution paths generally suggests many nested conditional statements and make the code less readible. This can usually be fixed by splitting the method into several smaller methods.

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

Loading history...
285
		$args = array( 'post_content' => $blob->content_import() );
286
		$meta = $blob->meta();
287
288
		$id = false;
289
290
		if ( ! empty( $meta ) ) {
291
			if ( array_key_exists( 'layout', $meta ) ) {
292
				$args['post_type'] = $meta['layout'];
293
				unset( $meta['layout'] );
294
			}
295
296
			if ( array_key_exists( 'published', $meta ) ) {
297
				$args['post_status'] = true === $meta['published'] ? 'publish' : 'draft';
298
				unset( $meta['published'] );
299
			}
300
301
			if ( array_key_exists( 'post_title', $meta ) ) {
302
				$args['post_title'] = $meta['post_title'];
303
				unset( $meta['post_title'] );
304
			}
305
306
			if ( array_key_exists( 'post_name', $meta ) ) {
307
				$args['post_name'] = $meta['post_name'];
308
				unset( $meta['post_name'] );
309
			}
310
311
			if ( array_key_exists( 'ID', $meta ) ) {
312
				$id = $args['ID'] = $meta['ID'];
313
				$blob->set_id($id);
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
314
				unset( $meta['ID'] );
315
			}
316
		}
317
318
		$meta['_wogh_sha'] = $blob->sha();
319
320
		if ( $id ) {
321
			$old_sha = get_post_meta( $id, '_wogh_sha', true );
322
			$old_github_path = get_post_meta( $id, '_wogh_github_path', true );
323
324
			// dont save post when has same sha
325
			if ( $old_sha  && $old_sha == $meta['_wogh_sha'] &&
326
				 $old_github_path && $old_github_path == $blob->path() ) {
327
				return false;
328
			}
329
		}
330
331
		$post = new Writing_On_GitHub_Post( $args, $this->app->api() );
332
		$post->set_old_github_path( $blob->path() );
333
		$post->set_meta( $meta );
334
		$blob->set_id( $post->id() );
335
336
		return $post;
337
	}
338
}
339