Completed
Push — master ( 647547...13dcfc )
by Devin
17:56
created

Give_Payment_Stats   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 211
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 54.26%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 211
rs 10
ccs 51
cts 94
cp 0.5426
wmc 17
lcom 1
cbo 1

3 Methods

Rating   Name   Duplication   Size   Complexity  
B get_sales() 0 48 6
D get_earnings() 0 106 10
A get_best_selling() 0 13 1
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 26 and the first side effect is on line 14.

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.

Loading history...
2
/**
3
 * Earnings / Sales Stats
4
 *
5
 * @package     Give
6
 * @subpackage  Classes/Stats
7
 * @copyright   Copyright (c) 2016, WordImpress
8
 * @license     http://opensource.org/licenses/gpl-2.0.php GNU Public License
9
 * @since       1.0
10
 */
11
12
// Exit if accessed directly
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit;
15
}
16
17
/**
18
 * Give_Stats Class
19
 *
20
 * This class is for retrieving stats for earnings and sales
21
 *
22
 * Stats can be retrieved for date ranges and pre-defined periods
23
 *
24
 * @since 1.0
25
 */
26
class Give_Payment_Stats extends Give_Stats {
27
28
29
	/**
30
	 * Retrieve sale stats
31
	 *
32
	 * @access public
33
	 * @since  1.0
34
	 *
35
	 * @param $form_id    INT The donation form to retrieve stats for. If false, gets stats for all forms
36
	 * @param $start_date string|bool The starting date for which we'd like to filter our sale stats. If false, we'll use the default start date of `this_month`
37
	 * @param $end_date   string|bool The end date for which we'd like to filter our sale stats. If false, we'll use the default end date of `this_month`
38
	 * @param $status     string|array The sale status(es) to count. Only valid when retrieving global stats
39
	 *
40
	 * @return float|int  Total amount of donations based on the passed arguments.
41
	 */
42 2
	public function get_sales( $form_id = 0, $start_date = false, $end_date = false, $status = 'publish' ) {
43
44 2
		$this->setup_dates( $start_date, $end_date );
45
46
		// Make sure start date is valid
47 2
		if ( is_wp_error( $this->start_date ) ) {
48
			return $this->start_date;
49
		}
50
51
		// Make sure end date is valid
52 2
		if ( is_wp_error( $this->end_date ) ) {
53
			return $this->end_date;
54
		}
55
56 2
		if ( empty( $form_id ) ) {
57
58
			// Global sale stats
59 2
			add_filter( 'give_count_payments_where', array( $this, 'count_where' ) );
60
61 2
			if ( is_array( $status ) ) {
62
				$count = 0;
63
				foreach ( $status as $payment_status ) {
64
					$count += give_count_payments()->$payment_status;
65
				}
66
			} else {
67 2
				$count = give_count_payments()->$status;
68
			}
69
70 2
			remove_filter( 'give_count_payments_where', array( $this, 'count_where' ) );
71
72 2
		} else {
73
74
			$this->timestamp = false;
75
76
			// Product specific stats
77
			global $give_logs;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
78
79
			add_filter( 'posts_where', array( $this, 'payments_where' ) );
80
81
			$count = $give_logs->get_log_count( $form_id, 'sale' );
82
83
			remove_filter( 'posts_where', array( $this, 'payments_where' ) );
84
85
		}
86
87 2
		return $count;
88
89
	}
90
91
92
	/**
93
	 * Retrieve earning stats
94
	 *
95
	 * @access public
96
	 * @since  1.0
97
	 *
98
	 * @param $form_id       INT The donation form to retrieve stats for. If false, gets stats for all forms
99
	 * @param $start_date    string|bool The starting date for which we'd like to filter our donation earnings stats. If false, we'll use the default start date of `this_month`
100
	 * @param $end_date      string|bool The end date for which we'd like to filter our sale stats. If false, we'll use the default end date of `this_month`
101
	 * @param $gateway_id    string|bool The gateway to get earnings for such as 'paypal' or 'stripe'
102
	 *
103
	 * @return float|int Total amount of donations based on the passed arguments.
104
	 */
105 2
	public function get_earnings( $form_id = 0, $start_date = false, $end_date = false, $gateway_id = false ) {
106
107 2
		global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
108
109 2
		$this->setup_dates( $start_date, $end_date );
110
111
		// Make sure start date is valid
112 2
		if ( is_wp_error( $this->start_date ) ) {
113
			return $this->start_date;
114
		}
115
116
		// Make sure end date is valid
117 2
		if ( is_wp_error( $this->end_date ) ) {
118
			return $this->end_date;
119
		}
120
121 2
		add_filter( 'posts_where', array( $this, 'payments_where' ) );
122
123 2
		if ( empty( $form_id ) ) {
124
125
			// Global earning stats
126
			$args = array(
127 2
				'post_type'              => 'give_payment',
128 2
				'nopaging'               => true,
129 2
				'post_status'            => array( 'publish' ),
130 2
				'fields'                 => 'ids',
131 2
				'update_post_term_cache' => false,
132 2
				'suppress_filters'       => false,
133 2
				'start_date'             => $this->start_date,
134
				// These dates are not valid query args, but they are used for cache keys
135 2
				'end_date'               => $this->end_date,
136 2
				'give_transient_type'    => 'give_earnings',
137
				// This is not a valid query arg, but is used for cache keying
138 2
			);
139
140
			//Filter by Gateway ID meta_key
141 2
			if ( $gateway_id !== false ) {
142
				$args['meta_key']   = '_give_payment_gateway';
143
				$args['meta_value'] = $gateway_id;
144
			}
145
146 2
			$args = apply_filters( 'give_stats_earnings_args', $args );
147 2
			$key  = 'give_stats_' . substr( md5( serialize( $args ) ), 0, 15 );
148 2
			$earnings = get_transient( $key );
149
			
150 2
			if ( false === $earnings ) {
151 2
				$sales    = get_posts( $args );
152 2
				$earnings = 0;
153 2
				if ( $sales ) {
154 2
					$sales = implode( ',', array_map('intval', $sales ) );
155 2
					$earnings += $wpdb->get_var( "SELECT SUM(meta_value) FROM $wpdb->postmeta WHERE meta_key = '_give_payment_total' AND post_id IN({$sales})" );
156 2
				}
157
				// Cache the results for one hour
158 2
				set_transient( $key, $earnings, HOUR_IN_SECONDS );
159 2
			}
160
161 2
		} else {
162
163
			// Donation form specific earning stats
164
			global $give_logs, $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
165
166
			$args = array(
167
				'post_parent'         => $form_id,
168
				'nopaging'            => true,
169
				'log_type'            => 'sale',
170
				'fields'              => 'ids',
171
				'suppress_filters'    => false,
172
				'start_date'          => $this->start_date,
173
				// These dates are not valid query args, but they are used for cache keys
174
				'end_date'            => $this->end_date,
175
				'give_transient_type' => 'give_earnings',
176
				// This is not a valid query arg, but is used for cache keying
177
			);
178
			$args = apply_filters( 'give_stats_earnings_args', $args );
179
			$key  = 'give_stats_' . substr( md5( serialize( $args ) ), 0, 15 );
180
			//Set transient for faster stats
181
			$earnings = get_transient( $key );
182
183
			if ( false === $earnings ) {
184
185
				$this->timestamp = false;
186
				$log_ids  = $give_logs->get_connected_logs( $args, 'sale' );
187
				$earnings = 0;
188
189
				if ( $log_ids ) {
190
					$log_ids     = implode( ',', array_map('intval', $log_ids ) );
191
					$payment_ids = $wpdb->get_col( "SELECT meta_value FROM $wpdb->postmeta WHERE meta_key='_give_log_payment_id' AND post_id IN ($log_ids);" );
192
193
					foreach ( $payment_ids as $payment_id ) {
194
						$earnings += give_get_payment_amount( $payment_id );
195
					}
196
					
197
				}
198
199
				// Cache the results for one hour
200
				set_transient( $key, $earnings, 60 * 60 );
201
			}
202
		}
203
204
		//remove our filter
205 2
		remove_filter( 'posts_where', array( $this, 'payments_where' ) );
206
207
		//return earnings
208 2
		return round( $earnings, give_currency_decimal_filter() );
209
210
	}
211
212
	/**
213
	 * Get the best selling Forms
214
	 *
215
	 * @access public
216
	 * @since  1.0
217
	 *
218
	 * @param $number int The number of results to retrieve with the default set to 10.
219
	 *
220
	 * @return array
221
	 */
222 1
	public function get_best_selling( $number = 10 ) {
223
224 1
		global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
225
226 1
		$give_forms = $wpdb->get_results( $wpdb->prepare(
227
			"SELECT post_id as form_id, max(meta_value) as sales
228 1
				FROM $wpdb->postmeta WHERE meta_key='_give_form_sales' AND meta_value > 0
229
				GROUP BY meta_value+0
230 1
				DESC LIMIT %d;", $number
231 1
		) );
232
233 1
		return $give_forms;
234
	}
235
236
}