Complex classes like WordPoints_Hook_Retroactive_Query 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 WordPoints_Hook_Retroactive_Query, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
162 | class WordPoints_Hook_Retroactive_Query implements WordPoints_Hook_Retroactive_QueryI { |
||
163 | |||
164 | protected $reaction; |
||
165 | |||
166 | protected $arg_hierarchy = array(); |
||
167 | |||
168 | protected $validator; |
||
169 | |||
170 | /** |
||
171 | * |
||
172 | * |
||
173 | * @since 1. |
||
174 | * |
||
175 | * @var WordPoints_Hierarchy |
||
176 | */ |
||
177 | protected $query; |
||
178 | |||
179 | /** |
||
180 | * |
||
181 | * |
||
182 | * @since 1. |
||
183 | * |
||
184 | * @var WordPoints_Hierarchy |
||
185 | */ |
||
186 | protected $queries; |
||
187 | |||
188 | /** |
||
189 | * |
||
190 | * |
||
191 | * @since 1. |
||
192 | * |
||
193 | * @var WordPoints_EntityishI |
||
194 | */ |
||
195 | protected $parent_arg; |
||
196 | |||
197 | protected $results; |
||
198 | |||
199 | public function __construct( WordPoints_Hook_ReactionI $reaction ) { |
||
200 | |||
201 | $this->reaction = $reaction; |
||
202 | $this->arg_hierarchy = new WordPoints_Hierarchy( 'sub_args' ); |
||
203 | $this->hooks = wordpoints_hooks(); |
||
204 | $this->entities = wordpoints_entities(); |
||
205 | $this->validator = new WordPoints_Hook_Reaction_Validator( $reaction, true ); |
||
206 | } |
||
207 | |||
208 | public function get_reaction() { |
||
209 | return $this->reaction; |
||
210 | } |
||
211 | |||
212 | public function get_validator() { |
||
215 | |||
216 | public function get_results() { |
||
229 | |||
230 | protected function execute() { |
||
243 | |||
244 | protected function prepare_query() { |
||
245 | |||
246 | $event_slug = $this->reaction->get_event_slug(); |
||
247 | |||
248 | $events = $this->hooks->get_sub_app( 'events' ); |
||
249 | $event = $events->get( $event_slug ); |
||
250 | |||
251 | if ( ! ( $event instanceof WordPoints_Hook_Event_RetroactiveI ) ) { |
||
252 | $this->validator->add_error( 'invalid hook' ); |
||
253 | } |
||
254 | |||
255 | foreach ( $events->get_sub_app( 'args' )->get_children( $event_slug ) as $arg ) { |
||
256 | $this->arg_hierarchy_push( // TODO |
||
257 | $arg |
||
258 | ); |
||
259 | } |
||
260 | |||
261 | if ( $event instanceof WordPoints_Hook_Retroactive_Query_ModifierI ) { |
||
262 | $event->modify_retroactive_query( $this ); |
||
263 | $this->reset(); |
||
264 | } |
||
265 | |||
266 | $reactor = $this->hooks->get_sub_app( 'reactors' )->get( $this->reaction->get_reactor_slug() ); |
||
267 | |||
268 | $reactor->modify_retroactive_query( $this ); |
||
269 | $this->reset(); |
||
270 | |||
271 | foreach ( $this->hooks->get_sub_app( 'extensions' )->get_all() as $extension ) { |
||
272 | |||
273 | if ( $extension instanceof WordPoints_Hook_Retroactive_Query_ModifierI ) { |
||
274 | $extension->modify_retroactive_query( $this ); |
||
275 | $this->reset(); |
||
276 | } |
||
277 | } |
||
278 | } |
||
279 | |||
280 | protected function perform_query() { |
||
281 | |||
282 | $this->queries = new WordPoints_Hierarchy( 'sub_queries' ); |
||
283 | $this->consolidate_queries( array( $this->arg_hierarchy->get() ) ); |
||
284 | unset( $this->query ); |
||
285 | |||
286 | $this->queries->reset(); |
||
287 | |||
288 | // Find the tip of a query. |
||
289 | $this->results = $this->execute_queries( $this->queries->get() ); |
||
290 | |||
291 | if ( is_wp_error( $this->results ) ) { |
||
292 | $this->validator->add_error( $this->results ); |
||
293 | } |
||
294 | } |
||
295 | |||
296 | protected function consolidate_queries( $arg_hierarchy, $storage_type = null ) { |
||
302 | |||
303 | protected function consolidate_query( $data ) { |
||
304 | |||
305 | if ( $data['storage_info']['type'] !== $this->queries->get_field( 'slug' ) ) { |
||
306 | |||
307 | $parent_id = null; |
||
308 | if ( isset( $this->query ) ) { |
||
309 | $parent_id = $this->query->get_id(); |
||
310 | } |
||
311 | |||
312 | $this->query = new WordPoints_Hierarchy( 'sub_args' ); |
||
313 | |||
314 | $this->queries->push( |
||
315 | $data['storage_info']['type'] |
||
316 | , array( 'query' => $this->query, 'parent_id' => $parent_id ) |
||
317 | ); |
||
318 | |||
319 | $pushed_query = true; |
||
320 | } |
||
321 | |||
322 | if ( isset( $data['sub_args'] ) ) { |
||
323 | $sub_args = $data['sub_args']; |
||
324 | unset( $data['sub_args'] ); |
||
325 | } |
||
326 | |||
327 | $this->query->push( $data['slug'], $data ); |
||
328 | |||
329 | if ( isset( $sub_args ) ) { |
||
330 | $this->consolidate_queries( $sub_args, $data['storage_info']['type'] ); |
||
331 | } |
||
332 | |||
333 | $this->query->pop(); |
||
334 | |||
335 | if ( ! empty( $pushed_query ) ) { |
||
336 | $this->queries->pop(); |
||
337 | $this->query = $this->queries->get_field( 'query' ); |
||
338 | } |
||
339 | } |
||
340 | |||
341 | protected function execute_queries( $queries ) { |
||
342 | |||
343 | /** @var WordPoints_HierarchyI $query */ |
||
344 | $query = $queries['query']; |
||
345 | |||
346 | if ( isset( $queries['sub_queries'] ) ) { |
||
347 | foreach ( $queries['sub_queries'] as $query_data ) { |
||
348 | |||
349 | $results = $this->execute_queries( $query_data ); |
||
350 | |||
351 | if ( is_wp_error( $results ) ) { |
||
352 | return $results; |
||
353 | } |
||
354 | |||
355 | if ( empty( $results ) ) { |
||
356 | return array(); |
||
357 | } |
||
358 | |||
359 | /** @var WordPoints_HierarchyI $child_query */ |
||
360 | $child_query = $query_data['query']; |
||
361 | $query->go_to( $query_data['parent_id'] ); |
||
362 | |||
363 | $condition = array( |
||
364 | // 'field' => $child_query->get_field( 'slug' ), |
||
365 | 'compare' => 'in', |
||
366 | 'value' => wp_list_pluck( |
||
367 | $results |
||
368 | , $child_query->get_field( 'storage_info', 'meta', 'id_field' ) |
||
369 | ), |
||
370 | ); |
||
371 | |||
372 | $query->push_to( 'conditions', $condition ); |
||
373 | } |
||
374 | } |
||
375 | |||
376 | $query->reset(); |
||
377 | $storage_type = $query->get_field( 'storage_info', 'type' ); |
||
378 | |||
379 | // it is pretty stupid to wait until now to figure this out. |
||
380 | $executor = $this->hooks->get_sub_app( 'retroactive_query_executors' )->get( $storage_type ); |
||
381 | |||
382 | if ( ! $executor ) { |
||
383 | $this->validator->add_error( |
||
384 | sprintf( 'unknown storage type "%s".', $storage_type ) |
||
385 | ); |
||
386 | } |
||
387 | |||
388 | return $executor->execute( array( $query->get() ) ); |
||
389 | } |
||
390 | |||
391 | protected function filter_results() { |
||
392 | |||
393 | $reactor = $this->hooks->get_sub_app( 'reactors' )->get( $this->reaction->get_reactor_slug() ); |
||
394 | |||
395 | if ( $reactor instanceof WordPoints_Hook_Retroactive_Query_FilterI ) { |
||
396 | $reactor->filter_retroactive_query( $this ); |
||
397 | } |
||
398 | |||
399 | foreach ( $this->hooks->get_sub_app( 'extensions' )->get_all() as $extension ) { |
||
400 | if ( $extension instanceof WordPoints_Hook_Retroactive_Query_FilterI ) { |
||
401 | $extension->filter_retroactive_query( $this ); |
||
402 | } |
||
403 | } |
||
404 | } |
||
405 | |||
406 | protected function group_results() { |
||
416 | |||
417 | public function add_condition( array $condition ) { |
||
421 | |||
422 | public function select_value( $data = array() ) { |
||
423 | |||
424 | $this->arg_hierarchy->set_field( 'select', $data ); |
||
425 | } |
||
426 | |||
427 | public function set_target( $target_arg ) { |
||
428 | |||
429 | foreach ( $target_arg as $arg_slug ) { |
||
430 | $this->arg_hierarchy_push( $arg_slug ); |
||
431 | } |
||
432 | |||
433 | // $id = $this->arg_hierarchy->get_id(); |
||
434 | // |
||
435 | // // If this entity has a parent relationship, we |
||
436 | // if ( $this->arg_hierarchy->ascend() ) { |
||
437 | // $field = $this->arg_hierarchy->get_field( 'storage_info', 'meta', 'field' ); |
||
438 | // $this->arg_hierarchy->ascend(); |
||
439 | // } else { |
||
440 | $field = $this->arg_hierarchy->get_field( 'storage_info', 'meta', 'id_field' ); |
||
441 | // } |
||
442 | |||
443 | $this->select_value( array( 'field' => $field, 'as' => 'target' ) ); |
||
444 | |||
445 | // $this->arg_hierarchy->go_to( $id ); |
||
446 | } |
||
447 | |||
448 | /** |
||
449 | * |
||
450 | * |
||
451 | * @since 1. |
||
452 | * @return WordPoints_EntityishI |
||
453 | */ |
||
454 | public function get_arg() { |
||
457 | |||
458 | public function arg_hierarchy_push( $slug ) { |
||
459 | |||
460 | $current_slug = $this->arg_hierarchy->get_field( 'slug' ); |
||
461 | |||
462 | if ( $current_slug === $slug && $this->arg_hierarchy->is_main() ) { |
||
463 | return; |
||
464 | } |
||
465 | |||
466 | // if ( $current_slug !== $slug ) { |
||
467 | |||
468 | if ( empty( $current_slug ) ) { |
||
469 | $arg = $this->entities->get( $slug ); |
||
470 | } else { |
||
471 | |||
472 | // If this child exists, don't overwrite it, just descend into it. |
||
473 | if ( $this->arg_hierarchy->has_child( $slug ) ) { |
||
474 | $this->arg_hierarchy->descend( $slug ); |
||
475 | return; |
||
476 | } |
||
477 | |||
478 | $parent_arg = $this->arg_hierarchy->get_field( 'arg' ); |
||
479 | |||
480 | if ( $parent_arg instanceof WordPoints_Entity_ParentI ) { |
||
481 | $arg = $parent_arg->get_child( $slug ); |
||
482 | } else { |
||
483 | return; // TODO |
||
484 | } |
||
485 | } |
||
486 | |||
487 | if ( $arg instanceof WordPoints_Entity_Array ) { |
||
488 | $arg = $this->entities->get( $arg->get_entity_slug() ); |
||
489 | } |
||
490 | |||
491 | $data['arg'] = $arg; |
||
492 | |||
493 | // TODO check if storage type is recognized? |
||
494 | $data['storage_info'] = $arg->get_storage_info(); |
||
495 | |||
496 | $this->arg_hierarchy->push( $slug, $data ); |
||
497 | |||
498 | // } else { |
||
499 | // $data = array(); |
||
500 | // } |
||
501 | } |
||
502 | |||
503 | public function arg_hierarchy_pop() { |
||
506 | |||
507 | public function reset() { |
||
510 | } |
||
511 | |||
512 | interface WordPoints_Hook_Retroactive_Query_FilterI { |
||
513 | public function filter_retroactive_query( WordPoints_Hook_Retroactive_QueryI $query ); |
||
514 | } |
||
515 | |||
516 | interface WordPoints_Hook_Retroactive_Query_ExecutorI { |
||
517 | public function execute( $query ); |
||
518 | } |
||
519 | |||
520 | /* |
||
793 |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.