Passed
Push — master ( c24352...fabb71 )
by Brian
14:05 queued 08:38
created

WPInv_Subscriptions   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 340
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 43
eloc 134
c 1
b 0
f 0
dl 0
loc 340
rs 8.96

13 Methods

Rating   Name   Duplication   Size   Complexity  
A setup_constants() 0 5 2
A notices() 0 33 6
A wpinv_subscriptions_list() 0 8 1
A __construct() 0 1 1
A instance() 0 8 2
A init() 0 5 1
A wpinv_post_actions() 0 3 2
A filters() 0 1 1
A wpinv_get_actions() 0 3 2
A actions() 0 9 1
B wpinv_process_cancellation() 0 44 7
B wpinv_get_pretty_subscription_frequency() 0 27 9
B add_subscription() 0 77 8

How to fix   Complexity   

Complex Class

Complex classes like WPInv_Subscriptions 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 WPInv_Subscriptions, and based on these observations, apply Extract Interface, too.

1
<?php
2
// Exit if accessed directly.
3
if (!defined( 'ABSPATH' ) ) exit;
4
5
function wpinv_subscription_init() {
6
    return WPInv_Subscriptions::instance();
7
}
8
add_action( 'plugins_loaded', 'wpinv_subscription_init', 100 );
9
10
/**
11
 * WPInv_Subscriptions Class.
12
 *
13
 * @since 1.0.0
14
 */
15
class WPInv_Subscriptions {
16
17
    private static $instance;
18
19
    /**
20
     * Main WPInv_Subscriptions Instance
21
     */
22
    public static function instance() {
23
        if ( ! isset( self::$instance ) ) {
24
            self::$instance = new WPInv_Subscriptions;
25
26
            self::$instance->init();
27
        }
28
29
        return self::$instance;
30
    }
31
32
    /**
33
     * Constructor -- prevent new instances
34
     *
35
     * @since 1.0.0
36
     */
37
    private function __construct(){
38
39
    }
40
41
    /**
42
     * Get things started
43
     *
44
     * Sets up inits actions and filters
45
     *
46
     * @since 1.0.0
47
     */
48
    function init() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
49
50
        self::setup_constants();
0 ignored issues
show
Bug Best Practice introduced by
The method WPInv_Subscriptions::setup_constants() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

50
        self::/** @scrutinizer ignore-call */ 
51
              setup_constants();
Loading history...
51
        self::actions();
0 ignored issues
show
Bug Best Practice introduced by
The method WPInv_Subscriptions::actions() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

51
        self::/** @scrutinizer ignore-call */ 
52
              actions();
Loading history...
52
        self::filters();
0 ignored issues
show
Bug Best Practice introduced by
The method WPInv_Subscriptions::filters() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

52
        self::/** @scrutinizer ignore-call */ 
53
              filters();
Loading history...
53
54
    }
55
56
    /**
57
     * Setup plugin constants.
58
     *
59
     * @access private
60
     * @since 1.0.0
61
     * @return void
62
     */
63
    private function setup_constants() {
64
65
        // Make sure CAL_GREGORIAN is defined.
66
        if ( ! defined( 'CAL_GREGORIAN' ) ) {
67
            define( 'CAL_GREGORIAN', 1 );
68
        }
69
    }
70
71
    /**
72
     * Add our actions
73
     *
74
     * @since  1.0.0
75
     * @return void
76
     */
77
    private function actions() {
78
79
        add_action( 'admin_menu', array( $this, 'wpinv_subscriptions_list' ), 40 );
80
        add_action( 'admin_notices', array( $this, 'notices' ) );
81
        add_action( 'init', array( $this, 'wpinv_post_actions' ) );
82
        add_action( 'init', array( $this, 'wpinv_get_actions' ) );
83
        add_action( 'wpinv_cancel_subscription', array( $this, 'wpinv_process_cancellation' ) );
84
        add_action( 'getpaid_checkout_before_gateway', array( $this, 'add_subscription' ), -999 );
85
        add_action( 'wpinv_subscriptions_front_notices', array( $this, 'notices' ) );
86
    }
87
88
    /**
89
     * Add our filters
90
     *
91
     * @since  1.0
92
     * @return void
93
     */
94
    private function filters() {
95
96
    }
97
98
    /**
99
     * Register our Subscriptions submenu
100
     *
101
     * @since  2.4
102
     * @return void
103
     */
104
    public function wpinv_subscriptions_list() {
105
        add_submenu_page(
106
            'wpinv',
107
            __( 'Subscriptions', 'invoicing' ),
108
            __( 'Subscriptions', 'invoicing' ),
109
            wpinv_get_capability(),
110
            'wpinv-subscriptions',
111
            'wpinv_subscriptions_page'
112
        );
113
    }
114
115
    public function notices() {
116
117
        if( empty( $_GET['wpinv-message'] ) ) {
118
            return;
119
        }
120
121
        $type    = 'updated';
122
        $message = '';
123
124
        switch( strtolower( $_GET['wpinv-message'] ) ) {
125
126
            case 'updated' :
127
128
                $message = __( 'Subscription updated successfully.', 'invoicing' );
129
130
                break;
131
132
            case 'deleted' :
133
134
                $message = __( 'Subscription deleted successfully.', 'invoicing' );
135
136
                break;
137
138
            case 'cancelled' :
139
140
                $message = __( 'Subscription cancelled successfully.', 'invoicing' );
141
142
                break;
143
144
        }
145
146
        if ( ! empty( $message ) ) {
147
            echo '<div class="' . esc_attr( $type ) . '"><p>' . $message . '</p></div>';
148
        }
149
150
    }
151
152
    /**
153
     * Every wpinv_action present in $_GET is called using WordPress's do_action function.
154
     * These functions are called on init.
155
     *
156
     * @since 1.0.0
157
     * @return void
158
     */
159
    function wpinv_get_actions() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
160
        if ( isset( $_GET['wpinv_action'] ) ) {
161
            do_action( 'wpinv_' . $_GET['wpinv_action'], $_GET );
162
        }
163
    }
164
165
    /**
166
     * Every wpinv_action present in $_POST is called using WordPress's do_action function.
167
     * These functions are called on init.
168
     *
169
     * @since 1.0.0
170
     * @return void
171
     */
172
    function wpinv_post_actions() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
173
        if ( isset( $_POST['wpinv_action'] ) ) {
174
            do_action( 'wpinv_' . $_POST['wpinv_action'], $_POST );
175
        }
176
    }
177
178
    /**
179
     * Get pretty subscription frequency
180
     *
181
     * @param $period
182
     * @param int $frequency_count The frequency of the period.
183
     * @return mixed|string|void
184
     */
185
    public static function wpinv_get_pretty_subscription_frequency( $period, $frequency_count = 1) {
186
187
        $frequency = '';
188
        //Format period details
189
        switch ( strtolower( $period ) ) {
190
            case 'day' :
191
            case 'd' :
192
                $frequency = sprintf( _n('%d Day', '%d Days', $frequency_count, 'invoicing'), $frequency_count);
193
                break;
194
            case 'week' :
195
            case 'w' :
196
                $frequency = sprintf( _n('%d Week', '%d Weeks', $frequency_count, 'invoicing'), $frequency_count);
197
                break;
198
            case 'month' :
199
            case 'm' :
200
                $frequency = sprintf( _n('%d Month', '%d Months', $frequency_count, 'invoicing'), $frequency_count);
201
                break;
202
            case 'year' :
203
            case 'y' :
204
                $frequency = sprintf( _n('%d Year', '%d Years', $frequency_count, 'invoicing'), $frequency_count);
205
                break;
206
            default :
207
                $frequency = apply_filters( 'wpinv_recurring_subscription_frequency', $frequency, $period, $frequency_count );
208
                break;
209
        }
210
211
        return $frequency;
212
213
    }
214
215
    /**
216
     * Handles cancellation requests for a subscription
217
     *
218
     * @access      public
219
     * @since       1.0.0
220
     * @return      void
221
     */
222
    public function wpinv_process_cancellation( $data ) {
223
224
225
        if( empty( $data['sub_id'] ) ) {
226
            return;
227
        }
228
229
        if( ! is_user_logged_in() ) {
230
            return;
231
        }
232
233
        if( ! wp_verify_nonce( $data['_wpnonce'], 'wpinv-recurring-cancel' ) ) {
234
            wp_die( __( 'Error', 'invoicing' ), __( 'Nonce verification failed', 'invoicing' ), array( 'response' => 403 ) );
235
        }
236
237
        $data['sub_id'] = absint( $data['sub_id'] );
238
        $subscription   = new WPInv_Subscription( $data['sub_id'] );
239
240
        if( ! $subscription->can_cancel() ) {
241
            wp_die( __( 'Error', 'invoicing' ), __( 'This subscription cannot be cancelled', 'invoicing' ), array( 'response' => 403 ) );
242
        }
243
244
        try {
245
246
            do_action( 'wpinv_recurring_cancel_' . $subscription->gateway . '_subscription', $subscription, true );
247
248
            $subscription->cancel();
249
250
            if( is_admin() ) {
251
252
                wp_redirect( admin_url( 'admin.php?page=wpinv-subscriptions&wpinv-message=cancelled&id=' . $subscription->id ) );
253
                exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
254
255
            } else {
256
257
                $redirect = remove_query_arg( array( '_wpnonce', 'wpinv_action', 'sub_id' ), add_query_arg( array( 'wpinv-message' => 'cancelled' ) ) );
258
                $redirect = apply_filters( 'wpinv_recurring_cancellation_redirect', $redirect, $subscription );
259
                wp_safe_redirect( $redirect );
260
                exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
261
262
            }
263
264
        } catch ( Exception $e ) {
265
            wp_die( __( 'Error', 'invoicing' ), $e->getMessage(), array( 'response' => 403 ) );
266
        }
267
268
    }
269
270
    /**
271
     * Creates a subscription on checkout
272
     *
273
     * @access      public
274
     * @param       WPInv_Invoice $invoice
275
     * @since       1.0.0
276
     * @return      void
277
     */
278
    public function add_subscription( $invoice ) {
279
280
        $invoice = new WPInv_Invoice( $invoice );
281
282
        // Abort if it is not recurring.
283
        if ( ! $invoice->is_recurring() || $invoice->is_renewal() ) {
284
            return;
285
        }
286
287
        // Should we create a subscription for the invoice?
288
        if ( apply_filters( 'wpinv_skip_invoice_subscription_creation', false, $invoice ) ) {
289
            return;
290
        }
291
292
        // Get the recurring item.
293
        $subscription_item = $invoice->get_recurring( true );
294
295
        // Prepare the subscription details.
296
        $period       = $subscription_item->get_recurring_period( true );
297
        $interval     = $subscription_item->get_recurring_interval();
298
        $add_period   = $interval . ' ' . $period;
299
        $trial_period = '';
300
301
        if ( $invoice->has_free_trial() ) {
302
303
            if ( $subscription_item->has_free_trial() ) {
304
                $trial_period   = $subscription_item->get_trial_period( true );
305
                $free_interval  = $subscription_item->get_trial_interval();
306
            } else {
307
                $trial_period   = $period;
308
                $free_interval  = $interval;
309
            }
310
311
            $trial_period   = $free_interval . ' ' . $trial_period;
312
            $add_period     = $trial_period;
313
314
        }
315
316
        // Calculate the next renewal date.
317
        $expiration = date( 'Y-m-d H:i:s', strtotime( "+ $add_period", current_time( 'timestamp' ) ) );
318
319
        // Subscription arguments.
320
        $args = array(
321
            'product_id'        => $subscription_item->get_id(),
322
            'customer_id'       => $invoice->get_user_id(),
323
            'parent_payment_id' => $invoice->get_id(),
324
            'status'            => $invoice->has_free_trial() ? 'trialling' : 'pending',
325
            'frequency'         => $interval,
326
            'period'            => $period,
327
            'initial_amount'    => $invoice->get_initial_total(),
328
            'recurring_amount'  => $invoice->get_recurring_total(),
329
            'bill_times'        => $subscription_item->get_recurring_limit(),
330
            'created'           => current_time( 'mysql' ),
331
            'expiration'        => $expiration,
332
            'trial_period'      => $trial_period,
333
            'profile_id'        => '',
334
            'transaction_id'    => '',
335
        );
336
337
        // Create or update the subscription.
338
        $subscription = wpinv_get_subscription( $invoice );
339
340
        if ( empty( $subscription ) ) {
341
342
            $subscription = new WPInv_Subscription();
343
            $subscription->create( $args );
344
345
        } else {
346
347
348
            unset( $args['transaction_id'] );
349
            unset( $args['profile_id'] );
350
            $subscription->update( $args );
351
352
        }
353
354
        return $subscription;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $subscription returns the type WPInv_Subscription|boolean which is incompatible with the documented return type void.
Loading history...
355
    }
356
}
357