Complex classes like Give_Customer 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 Give_Customer, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 22 | class Give_Customer { |
||
| 23 | |||
| 24 | /** |
||
| 25 | * The customer ID |
||
| 26 | * |
||
| 27 | * @since 1.0 |
||
| 28 | */ |
||
| 29 | public $id = 0; |
||
| 30 | |||
| 31 | /** |
||
| 32 | * The customer's purchase count |
||
| 33 | * |
||
| 34 | * @since 1.0 |
||
| 35 | */ |
||
| 36 | public $purchase_count = 0; |
||
| 37 | |||
| 38 | /** |
||
| 39 | * The customer's lifetime value |
||
| 40 | * |
||
| 41 | * @since 1.0 |
||
| 42 | */ |
||
| 43 | public $purchase_value = 0; |
||
| 44 | |||
| 45 | /** |
||
| 46 | * The customer's email |
||
| 47 | * |
||
| 48 | * @since 1.0 |
||
| 49 | */ |
||
| 50 | public $email; |
||
| 51 | |||
| 52 | /** |
||
| 53 | * The customer's name |
||
| 54 | * |
||
| 55 | * @since 1.0 |
||
| 56 | */ |
||
| 57 | public $name; |
||
| 58 | |||
| 59 | /** |
||
| 60 | * The customer's creation date |
||
| 61 | * |
||
| 62 | * @since 1.0 |
||
| 63 | */ |
||
| 64 | public $date_created; |
||
| 65 | |||
| 66 | /** |
||
| 67 | * The payment IDs associated with the customer |
||
| 68 | * |
||
| 69 | * @since 1.0 |
||
| 70 | */ |
||
| 71 | public $payment_ids; |
||
| 72 | |||
| 73 | /** |
||
| 74 | * The user ID associated with the customer |
||
| 75 | * |
||
| 76 | * @since 1.0 |
||
| 77 | */ |
||
| 78 | public $user_id; |
||
| 79 | |||
| 80 | /** |
||
| 81 | * Customer Notes |
||
| 82 | * |
||
| 83 | * @since 1.0 |
||
| 84 | */ |
||
| 85 | public $notes; |
||
| 86 | |||
| 87 | /** |
||
| 88 | * The Database Abstraction |
||
| 89 | * |
||
| 90 | * @since 1.0 |
||
| 91 | */ |
||
| 92 | protected $db; |
||
| 93 | |||
| 94 | /** |
||
| 95 | * Give_Customer constructor. |
||
| 96 | * |
||
| 97 | * @param bool $_id_or_email |
||
| 98 | * @param bool $by_user_id |
||
| 99 | */ |
||
| 100 | 52 | public function __construct( $_id_or_email = false, $by_user_id = false ) { |
|
| 125 | |||
| 126 | /** |
||
| 127 | * Given the customer data, let's set the variables |
||
| 128 | * |
||
| 129 | * @since 1.0 |
||
| 130 | * |
||
| 131 | * @param object $customer The Customer Object |
||
| 132 | * |
||
| 133 | * @return bool If the setup was successful or not |
||
| 134 | */ |
||
| 135 | 52 | private function setup_customer( $customer ) { |
|
| 165 | |||
| 166 | /** |
||
| 167 | * Magic __get function to dispatch a call to retrieve a private property |
||
| 168 | * |
||
| 169 | * @since 1.0 |
||
| 170 | */ |
||
| 171 | 1 | public function __get( $key ) { |
|
| 184 | |||
| 185 | /** |
||
| 186 | * Creates a customer |
||
| 187 | * |
||
| 188 | * @since 1.0 |
||
| 189 | * |
||
| 190 | * @param array $data Array of attributes for a customer |
||
| 191 | * |
||
| 192 | * @return mixed False if not a valid creation, Customer ID if user is found or valid creation |
||
| 193 | */ |
||
| 194 | 53 | public function create( $data = array() ) { |
|
| 195 | |||
| 196 | 53 | if ( $this->id != 0 || empty( $data ) ) { |
|
| 197 | return false; |
||
| 198 | } |
||
| 199 | |||
| 200 | $defaults = array( |
||
| 201 | 'payment_ids' => '' |
||
| 202 | 53 | ); |
|
| 203 | |||
| 204 | 53 | $args = wp_parse_args( $data, $defaults ); |
|
| 205 | 53 | $args = $this->sanitize_columns( $args ); |
|
| 206 | |||
| 207 | 53 | if ( empty( $args['email'] ) || ! is_email( $args['email'] ) ) { |
|
| 208 | 1 | return false; |
|
| 209 | } |
||
| 210 | |||
| 211 | 53 | if ( ! empty( $args['payment_ids'] ) && is_array( $args['payment_ids'] ) ) { |
|
| 212 | $args['payment_ids'] = implode( ',', array_unique( array_values( $args['payment_ids'] ) ) ); |
||
| 213 | } |
||
| 214 | |||
| 215 | 53 | do_action( 'give_customer_pre_create', $args ); |
|
| 216 | |||
| 217 | 53 | $created = false; |
|
| 218 | |||
| 219 | // The DB class 'add' implies an update if the customer being asked to be created already exists |
||
| 220 | 53 | if ( $this->db->add( $data ) ) { |
|
| 221 | |||
| 222 | // We've successfully added/updated the customer, reset the class vars with the new data |
||
| 223 | 53 | $customer = $this->db->get_customer_by( 'email', $args['email'] ); |
|
| 224 | |||
| 225 | // Setup the customer data with the values from DB |
||
| 226 | 53 | $this->setup_customer( $customer ); |
|
| 227 | |||
| 228 | 53 | $created = $this->id; |
|
| 229 | 53 | } |
|
| 230 | |||
| 231 | 53 | do_action( 'give_customer_post_create', $created, $args ); |
|
| 232 | |||
| 233 | 53 | return $created; |
|
| 234 | |||
| 235 | } |
||
| 236 | |||
| 237 | /** |
||
| 238 | * Update a customer record |
||
| 239 | * |
||
| 240 | * @since 1.0 |
||
| 241 | * |
||
| 242 | * @param array $data Array of data attributes for a customer (checked via whitelist) |
||
| 243 | * |
||
| 244 | * @return bool If the update was successful or not |
||
| 245 | */ |
||
| 246 | 53 | public function update( $data = array() ) { |
|
| 270 | |||
| 271 | |||
| 272 | /** |
||
| 273 | * Attach payment to the customer then triggers increasing stats |
||
| 274 | * |
||
| 275 | * @since 1.0 |
||
| 276 | * |
||
| 277 | * @param int $payment_id The payment ID to attach to the customer |
||
| 278 | * @param bool $update_stats For backwards compatibility, if we should increase the stats or not |
||
| 279 | * |
||
| 280 | * @return bool If the attachment was successfuly |
||
| 281 | */ |
||
| 282 | 52 | public function attach_payment( $payment_id = 0, $update_stats = true ) { |
|
| 331 | |||
| 332 | |||
| 333 | /** |
||
| 334 | * Remove a payment from this customer, then triggers reducing stats |
||
| 335 | * |
||
| 336 | * @since 1.0 |
||
| 337 | * |
||
| 338 | * @param integer $payment_id The Payment ID to remove |
||
| 339 | * @param bool $update_stats For backwards compatibility, if we should increase the stats or not |
||
| 340 | * |
||
| 341 | * @return boolean If the removal was successful |
||
| 342 | */ |
||
| 343 | 3 | public function remove_payment( $payment_id = 0, $update_stats = true ) { |
|
| 399 | |||
| 400 | /** |
||
| 401 | * Increase the purchase count of a customer |
||
| 402 | * |
||
| 403 | * @since 1.0 |
||
| 404 | * |
||
| 405 | * @param integer $count The number to increment by |
||
| 406 | * |
||
| 407 | * @return int The purchase count |
||
| 408 | */ |
||
| 409 | 42 | public function increase_purchase_count( $count = 1 ) { |
|
| 428 | |||
| 429 | /** |
||
| 430 | * Decrease the customer purchase count |
||
| 431 | * |
||
| 432 | * @since 1.0 |
||
| 433 | * |
||
| 434 | * @param integer $count The amount to decrease by |
||
| 435 | * |
||
| 436 | * @return mixed If successful, the new count, otherwise false |
||
| 437 | */ |
||
| 438 | 6 | public function decrease_purchase_count( $count = 1 ) { |
|
| 461 | |||
| 462 | /** |
||
| 463 | * Increase the customer's lifetime value |
||
| 464 | * |
||
| 465 | * @since 1.0 |
||
| 466 | * |
||
| 467 | * @param float $value The value to increase by |
||
| 468 | * |
||
| 469 | * @return mixed If successful, the new value, otherwise false |
||
| 470 | */ |
||
| 471 | 42 | public function increase_value( $value = 0.00 ) { |
|
| 485 | |||
| 486 | /** |
||
| 487 | * Decrease a customer's lifetime value |
||
| 488 | * |
||
| 489 | * @since 1.0 |
||
| 490 | * |
||
| 491 | * @param float $value The value to decrease by |
||
| 492 | * |
||
| 493 | * @return mixed If successful, the new value, otherwise false |
||
| 494 | */ |
||
| 495 | 7 | public function decrease_value( $value = 0.00 ) { |
|
| 513 | |||
| 514 | /** |
||
| 515 | * Get the parsed notes for a customer as an array |
||
| 516 | * |
||
| 517 | * @since 1.0 |
||
| 518 | * |
||
| 519 | * @param integer $length The number of notes to get |
||
| 520 | * @param integer $paged What note to start at |
||
| 521 | * |
||
| 522 | * @return array The notes requsted |
||
| 523 | */ |
||
| 524 | 52 | public function get_notes( $length = 20, $paged = 1 ) { |
|
| 537 | |||
| 538 | /** |
||
| 539 | * Get the total number of notes we have after parsing |
||
| 540 | * |
||
| 541 | * @since 1.0 |
||
| 542 | * @return int The number of notes for the customer |
||
| 543 | */ |
||
| 544 | 1 | public function get_notes_count() { |
|
| 552 | |||
| 553 | /** |
||
| 554 | * Add a note for the customer |
||
| 555 | * |
||
| 556 | * @since 1.0 |
||
| 557 | * |
||
| 558 | * @param string $note The note to add |
||
| 559 | * |
||
| 560 | * @return string|boolean The new note if added succesfully, false otherwise |
||
| 561 | */ |
||
| 562 | 1 | public function add_note( $note = '' ) { |
|
| 593 | |||
| 594 | /** |
||
| 595 | * Get the notes column for the customer |
||
| 596 | * |
||
| 597 | * @since 1.0 |
||
| 598 | * @return string The Notes for the customer, non-parsed |
||
| 599 | */ |
||
| 600 | 52 | private function get_raw_notes() { |
|
| 607 | |||
| 608 | /** |
||
| 609 | * Sanitize the data for update/create |
||
| 610 | * |
||
| 611 | * @since 1.0 |
||
| 612 | * |
||
| 613 | * @param array $data The data to sanitize |
||
| 614 | * |
||
| 615 | * @return array The sanitized data, based off column defaults |
||
| 616 | */ |
||
| 617 | 52 | private function sanitize_columns( $data ) { |
|
| 670 | |||
| 671 | } |
||
| 672 |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.