Passed
Push — ci ( 9054a2...49f094 )
by litefeel
03:00
created

lib/import.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
	public function payload( Writing_On_GitHub_Payload $payload ) {
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
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) {
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
	public function master() {
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
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 ) {
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' ) {
151
				if ( $blob->id() ) {
152
					$idsmap[$blob->id()] = true;
153
				}
154
			} elseif ( $post != false ) {
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 &&
202
			 strncasecmp($file->path, '_posts/', strlen('_posts/') ) != 0 &&
203
			 strncasecmp($file->path, 'images/', strlen('images/') ) != 0 ) {
204
			return false;
205
		}
206
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() ) {
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) {
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) ) {
265
				unlink($path);
266
			}
267
		} else {
268
			$dirname = dirname($path);
269
			if ( ! file_exists($dirname) ) {
270
				wp_mkdir_p($dirname);
271
			}
272
273
			file_put_contents($path, $blob->content());
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 ) {
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);
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