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 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 |
||
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 ) { |
||
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 ) { |
|
54 | |||
55 | /** |
||
56 | * import blob by files |
||
57 | * @param Writing_On_GitHub_File_Info[] $files |
||
58 | * |
||
59 | * @return string|WP_Error |
||
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 | View Code Duplication | 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 |
||
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 ) { |
||
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 ) { |
||
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 ) { |
||
338 | } |
||
339 |
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.