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 Give_Donation_Stats 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_Donation_Stats, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 26 | class Give_Donation_Stats extends Give_Stats { |
||
| 27 | /** |
||
| 28 | * Give_Donation_Stats constructor. |
||
| 29 | * |
||
| 30 | * @param array $query |
||
| 31 | */ |
||
| 32 | public function __construct( array $query = array() ) { |
||
| 42 | |||
| 43 | /** |
||
| 44 | * Retrieve sale stats |
||
| 45 | * |
||
| 46 | * @since 2.4.1 |
||
| 47 | * @access public |
||
| 48 | * |
||
| 49 | * @param array $query |
||
| 50 | * |
||
| 51 | * @return stdClass |
||
| 52 | */ |
||
| 53 | public function get_sales( $query = array() ) { |
||
| 110 | |||
| 111 | |||
| 112 | /** |
||
| 113 | * Retrieve earning stats |
||
| 114 | * |
||
| 115 | * @since 2.4.1 |
||
| 116 | * @access public |
||
| 117 | * |
||
| 118 | * @param array $query |
||
| 119 | * |
||
| 120 | * @return stdClass |
||
| 121 | */ |
||
| 122 | public function get_earnings( $query = array() ) { |
||
| 186 | |||
| 187 | /** |
||
| 188 | * Get donation earning and sales information |
||
| 189 | * |
||
| 190 | * @since 2.4.1 |
||
| 191 | * @access public |
||
| 192 | * |
||
| 193 | * @param array $query |
||
| 194 | * |
||
| 195 | * @return stdClass |
||
| 196 | */ |
||
| 197 | public function get_donation_statistics( $query = array() ) { |
||
| 198 | $day_by_day = true; |
||
| 199 | |||
| 200 | $this->query_vars['table'] = $this->get_db()->posts; |
||
| 201 | $this->query_vars['column'] = 'post_date_gmt'; |
||
| 202 | |||
| 203 | $column = "{$this->query_vars['table']}.{$this->query_vars['column']}"; |
||
| 204 | |||
| 205 | $sql_clauses = array( |
||
| 206 | 'select' => "YEAR({$column}) AS year, MONTH({$column}) AS month, DAY({$column}) AS day", |
||
| 207 | 'groupby' => "YEAR({$column}), MONTH({$column}), DAY({$column})", |
||
| 208 | 'orderby' => "YEAR({$column}), MONTH({$column}), DAY({$column})", |
||
| 209 | ); |
||
| 210 | |||
|
|
|||
| 211 | |||
| 212 | $this->pre_query( $query ); |
||
| 213 | |||
| 214 | $sql = "SELECT COUNT(ID) AS sales, SUM(m1.meta_value) AS earnings, {$sql_clauses['select']} |
||
| 215 | FROM {$this->query_vars['table']} |
||
| 216 | INNER JOIN {$this->get_db()->donationmeta} as m1 on m1.donation_id={$this->query_vars['table']}.{$this->query_vars['inner_join_at']} |
||
| 217 | {$this->query_vars['where_sql']} |
||
| 218 | AND m1.meta_key='_give_payment_total' |
||
| 219 | {$this->query_vars['date_sql']} |
||
| 220 | GROUP BY {$sql_clauses['groupby']} |
||
| 221 | ORDER BY {$sql_clauses['orderby']} ASC"; |
||
| 222 | |||
| 223 | $results = $this->get_db()->get_results( $sql ); |
||
| 224 | |||
| 225 | $sales = array(); |
||
| 226 | $earnings = array(); |
||
| 227 | $dates = array( |
||
| 228 | 'start' => $this->query_vars['start_date'], |
||
| 229 | 'end' => $this->query_vars['end_date'] |
||
| 230 | ); |
||
| 231 | |||
| 232 | // Initialise all arrays with timestamps and set values to 0. |
||
| 233 | while ( strtotime( $dates['start']->copy()->format( 'mysql' ) ) <= strtotime( $dates['end']->copy()->format( 'mysql' ) ) ) { |
||
| 234 | $day = ( true === $day_by_day ) |
||
| 235 | ? $dates['start']->day |
||
| 236 | : 1; |
||
| 237 | |||
| 238 | $timestamp = Give_Date::create( $dates['start']->year, $dates['start']->month, $day, 0, 0, 0, $this->date->getWpTimezone() )->timestamp; |
||
| 239 | |||
| 240 | $sales[ $timestamp ]['x'] = $earnings[ $timestamp ]['x'] = $timestamp * 1000; |
||
| 241 | $sales[ $timestamp ]['y'] = 0; |
||
| 242 | $earnings[ $timestamp ]['y'] = 0.00; |
||
| 243 | |||
| 244 | $dates['start'] = ( true === $day_by_day ) |
||
| 245 | ? $dates['start']->addDays( 1 ) |
||
| 246 | : $dates['start']->addMonth( 1 ); |
||
| 247 | } |
||
| 248 | |||
| 249 | foreach ( $results as $result ) { |
||
| 250 | $day = ( true === $day_by_day ) |
||
| 251 | ? $result->day |
||
| 252 | : 1; |
||
| 253 | |||
| 254 | $timestamp = Give_Date::create( $result->year, $result->month, $day, 0, 0, 0, $this->date->getWpTimezone() )->timestamp; |
||
| 255 | |||
| 256 | $sales[ $timestamp ]['y'] = $result->sales; |
||
| 257 | $earnings[ $timestamp ]['y'] = floatval( $result->earnings ); |
||
| 258 | } |
||
| 259 | |||
| 260 | $sales = array_values( $sales ); |
||
| 261 | $earnings = array_values( $earnings ); |
||
| 262 | |||
| 263 | $results = new stdClass(); |
||
| 264 | |||
| 265 | $results->sales = $sales; |
||
| 266 | $results->earnings = $earnings; |
||
| 267 | |||
| 268 | // Set query_vars in result |
||
| 269 | $results->query_vars = $this->query_vars; |
||
| 270 | |||
| 271 | $this->reset_query(); |
||
| 272 | |||
| 273 | return $results; |
||
| 274 | } |
||
| 275 | |||
| 276 | /** |
||
| 277 | * Get the best selling forms |
||
| 278 | * |
||
| 279 | * @since 2.4.1 |
||
| 280 | * @access public |
||
| 281 | * |
||
| 282 | * @param array $query Array of query arguments |
||
| 283 | * |
||
| 284 | * @return string |
||
| 285 | */ |
||
| 286 | public function get_busiest_day( $query = array() ) { |
||
| 313 | |||
| 314 | /** |
||
| 315 | * Get the best selling forms |
||
| 316 | * @todo : make this function dynamic with new api |
||
| 317 | * |
||
| 318 | * @since 2.4.1 |
||
| 319 | * @access public |
||
| 320 | * @global wpdb $wpdb |
||
| 321 | * |
||
| 322 | * @param $number int The number of results to retrieve with the default set to 10. |
||
| 323 | * |
||
| 324 | * @return array Best selling forms |
||
| 325 | */ |
||
| 326 | public function get_best_selling( $number = 10 ) { |
||
| 339 | |||
| 340 | /** |
||
| 341 | * Get most valuable cause |
||
| 342 | * |
||
| 343 | * @since 2.4.1 |
||
| 344 | * @access public |
||
| 345 | * |
||
| 346 | * @param array $query |
||
| 347 | * |
||
| 348 | * @return int |
||
| 349 | */ |
||
| 350 | public function get_most_valuable_cause( $query = array() ) { |
||
| 378 | |||
| 379 | /** |
||
| 380 | * Calculate number of refunded donations. |
||
| 381 | * |
||
| 382 | * @since 2.4.1 |
||
| 383 | * @acess public |
||
| 384 | * |
||
| 385 | * @param array $query |
||
| 386 | * |
||
| 387 | * @return stdClass |
||
| 388 | */ |
||
| 389 | View Code Duplication | public function get_refund_count( $query = array() ) { |
|
| 396 | |||
| 397 | /** |
||
| 398 | * Calculate amount of refunded donations. |
||
| 399 | * |
||
| 400 | * @since 2.4.1 |
||
| 401 | * @acess public |
||
| 402 | * |
||
| 403 | * @param array $query |
||
| 404 | * |
||
| 405 | * @return stdClass |
||
| 406 | */ |
||
| 407 | View Code Duplication | public function get_refund( $query = array() ) { |
|
| 414 | |||
| 415 | /** |
||
| 416 | * Set meta query |
||
| 417 | * |
||
| 418 | * @since 2.4.1 |
||
| 419 | * @access public |
||
| 420 | * |
||
| 421 | * @param string $query_key |
||
| 422 | * @param string $meta_key |
||
| 423 | * |
||
| 424 | */ |
||
| 425 | private function set_meta_sql( $query_key, $meta_key ) { |
||
| 446 | |||
| 447 | /** |
||
| 448 | * Pre process query |
||
| 449 | * |
||
| 450 | * @since 2.4.1 |
||
| 451 | * @access protected |
||
| 452 | * |
||
| 453 | * @param array $query |
||
| 454 | */ |
||
| 455 | protected function pre_query( $query = array() ) { |
||
| 512 | |||
| 513 | } |
||
| 514 | |||
| 524 |