Completed
Branch BUG/10297/invoice-payment-meth... (96872c)
by
unknown
60:38 queued 48:52
created

EE_Payment_Method_Manager   B

Complexity

Total Complexity 54

Size/Duplication

Total Lines 577
Duplicated Lines 1.39 %

Coupling/Cohesion

Components 2
Dependencies 12

Importance

Changes 0
Metric Value
dl 8
loc 577
rs 7.0642
c 0
b 0
f 0
wmc 54
lcom 2
cbo 12

21 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 14 2
A instance() 0 9 2
A reset() 0 5 1
A maybe_register_payment_methods() 0 6 3
B _register_payment_methods() 0 24 2
B register_payment_method() 8 38 3
B payment_method_type_exists() 0 15 5
A payment_method_type_names() 0 13 3
B payment_method_types() 0 12 5
A payment_method_type_sans_class_prefix() 0 4 1
A payment_method_class_from_type() 0 4 1
B activate_a_payment_method_of_type() 0 54 6
A create_payment_method_of_type() 0 17 1
B initialize_payment_method() 0 20 5
A set_usable_currencies_on_payment_method() 0 12 1
A deactivate_payment_method() 0 20 1
A initializePaymentMethodCaps() 0 11 2
A getPaymentMethodCaps() 0 8 2
B addPaymentMethodCap() 0 28 4
A addPaymentMethodCapsDuringReset() 0 8 3
A add_payment_method_caps() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

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 Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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

1
<?php 
2
3
use EventEspresso\core\domain\entities\notifications\PersistentAdminNotice;
4
use EventEspresso\core\exceptions\InvalidDataTypeException;
5
use EventEspresso\core\interfaces\ResettableInterface;
6
7
defined('EVENT_ESPRESSO_VERSION') || exit('No direct script access allowed');
8
9
10
11
/**
12
 * Class EE_Payment_Method_Manager
13
 * Used for finding all payment method types that can be defined.
14
 * Allows addons to easily add other payment methods
15
 *
16
 * @package       Event Espresso
17
 * @subpackage    core
18
 * @author        Michael Nelson
19
 * @since         4.5
20
 */
21
class EE_Payment_Method_Manager implements ResettableInterface
22
{
23
24
    /**
25
     * prefix added to all payment method capabilities names
26
     */
27
    const   CAPABILITIES_PREFIX= 'ee_payment_method_';
28
29
    /**
30
     * @var EE_Payment_Method_Manager $_instance
31
     */
32
    private static $_instance;
33
34
    /**
35
     * @var boolean
36
     */
37
    protected $payment_method_caps_initialized = false;
38
39
    /**
40
     * @var array keys are class names without 'EE_PMT_', values are their filepaths
41
     */
42
    protected $_payment_method_types = array();
43
44
    /**
45
     * @var EE_PMT_Base[]
46
     */
47
    protected $payment_method_objects = array();
48
49
50
51
    /**
52
     * EE_Payment_Method_Manager constructor.
53
     *
54
     * @throws EE_Error
55
     * @throws DomainException
56
     */
57
    public function __construct()
58
    {
59
        // if in admin lets ensure caps are set.
60
        if (is_admin()) {
61
            $this->_register_payment_methods();
62
            // set them immediately
63
            $this->initializePaymentMethodCaps();
64
            // plus any time they get reset
65
            add_filter(
66
                'FHEE__EE_Capabilities__addCaps__capabilities_to_add',
67
                array($this, 'addPaymentMethodCapsDuringReset')
68
            );
69
        }
70
    }
71
72
73
74
    /**
75
     * @singleton method used to instantiate class object
76
     * @return EE_Payment_Method_Manager instance
77
     * @throws DomainException
78
     * @throws EE_Error
79
     */
80
    public static function instance()
81
    {
82
        // check if class object is instantiated, and instantiated properly
83
        if (! self::$_instance instanceof EE_Payment_Method_Manager) {
84
            EE_Registry::instance()->load_lib('PMT_Base');
85
            self::$_instance = new self();
86
        }
87
        return self::$_instance;
88
    }
89
90
91
92
    /**
93
     * Resets the instance and returns a new one
94
     *
95
     * @return EE_Payment_Method_Manager
96
     * @throws DomainException
97
     * @throws EE_Error
98
     */
99
    public static function reset()
100
    {
101
        self::$_instance = null;
102
        return self::instance();
103
    }
104
105
106
107
    /**
108
     * If necessary, re-register payment methods
109
     *
110
     * @param boolean $force_recheck whether to recheck for payment method types,
111
     *                               or just re-use the PMTs we found last time we checked during this request (if
112
     *                               we have not yet checked during this request, then we need to check anyways)
113
     */
114
    public function maybe_register_payment_methods($force_recheck = false)
115
    {
116
        if (! $this->_payment_method_types || $force_recheck) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->_payment_method_types of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
117
            $this->_register_payment_methods();
118
        }
119
    }
120
121
122
123
    /**
124
     * register_payment_methods
125
     *
126
     * @return array
127
     */
128
    protected function _register_payment_methods()
129
    {
130
        // grab list of installed modules
131
        $pm_to_register = glob(EE_PAYMENT_METHODS . '*', GLOB_ONLYDIR);
132
        // filter list of modules to register
133
        $pm_to_register = apply_filters(
134
            'FHEE__EE_Payment_Method_Manager__register_payment_methods__payment_methods_to_register',
135
            $pm_to_register
136
        );
137
        // remove any duplicates if that should happen for some reason
138
        $pm_to_register = array_unique($pm_to_register);
139
        // loop through folders
140
        foreach ($pm_to_register as $pm_path) {
141
            $this->register_payment_method($pm_path);
142
        }
143
        do_action('FHEE__EE_Payment_Method_Manager__register_payment_methods__registered_payment_methods');
144
        // filter list of installed modules
145
        //keep them organized alphabetically by the payment method type's name
146
        ksort($this->_payment_method_types);
147
        return apply_filters(
148
            'FHEE__EE_Payment_Method_Manager__register_payment_methods__installed_payment_methods',
149
            $this->_payment_method_types
150
        );
151
    }
152
153
154
155
    /**
156
     * register_payment_method- makes core aware of this payment method
157
     *
158
     * @param string $payment_method_path - full path up to and including payment method folder
159
     * @return boolean
160
     */
161
    public function register_payment_method($payment_method_path = '')
162
    {
163
        do_action('AHEE__EE_Payment_Method_Manager__register_payment_method__begin', $payment_method_path);
164
        $module_ext = '.pm.php';
165
        // make all separators match
166
        $payment_method_path = rtrim(str_replace('/\\', DS, $payment_method_path), DS);
167
        // grab and sanitize module name
168
        $module_dir = basename($payment_method_path);
169
        // create class name from module directory name
170
        $module = str_replace(array('_', ' '), array(' ', '_'), $module_dir);
171
        // add class prefix
172
        $module_class = 'EE_PMT_' . $module;
173
        // does the module exist ?
174
        if (! is_readable($payment_method_path . DS . $module_class . $module_ext)) {
175
            $msg = sprintf(
176
                esc_html__(
177
                    'The requested %s payment method file could not be found or is not readable due to file permissions.',
178
                    'event_espresso'
179
                ), $module
180
            );
181
            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
182
            return false;
183
        }
184
        // load the module class file
185
        require_once($payment_method_path . DS . $module_class . $module_ext);
186
        // verify that class exists
187 View Code Duplication
        if (! class_exists($module_class)) {
188
            $msg = sprintf(
189
                esc_html__('The requested %s module class does not exist.', 'event_espresso'),
190
                $module_class
191
            );
192
            EE_Error::add_error($msg . '||' . $msg, __FILE__, __FUNCTION__, __LINE__);
193
            return false;
194
        }
195
        // add to array of registered modules
196
        $this->_payment_method_types[$module] = $payment_method_path . DS . $module_class . $module_ext;
197
        return true;
198
    }
199
200
201
202
    /**
203
     * Checks if a payment method has been registered, and if so includes it
204
     *
205
     * @param string  $payment_method_name like 'PayPal_Pro', (ie class name without the prefix 'EEPM_')
206
     * @param boolean $force_recheck       whether to force re-checking for new payment method types
207
     * @return boolean
208
     */
209
    public function payment_method_type_exists($payment_method_name, $force_recheck = false)
210
    {
211
        if (
212
            $force_recheck
213
            || ! is_array($this->_payment_method_types)
214
            || ! isset($this->_payment_method_types[$payment_method_name])
215
        ) {
216
            $this->maybe_register_payment_methods($force_recheck);
217
        }
218
        if (isset($this->_payment_method_types[$payment_method_name])) {
219
            require_once($this->_payment_method_types[$payment_method_name]);
220
            return true;
221
        }
222
        return false;
223
    }
224
225
226
227
    /**
228
     * Returns all the class names of the various payment method types
229
     *
230
     * @param boolean $with_prefixes TRUE: get payment method type class names; false just their 'names'
231
     *                               (what you'd find in wp_esp_payment_method.PMD_type)
232
     * @param boolean $force_recheck whether to force re-checking for new payment method types
233
     * @return array
234
     */
235
    public function payment_method_type_names($with_prefixes = false, $force_recheck = false)
236
    {
237
        $this->maybe_register_payment_methods($force_recheck);
238
        if ($with_prefixes) {
239
            $classnames = array_keys($this->_payment_method_types);
240
            $payment_methods = array();
241
            foreach ($classnames as $classname) {
242
                $payment_methods[] = $this->payment_method_class_from_type($classname);
243
            }
244
            return $payment_methods;
245
        }
246
        return array_keys($this->_payment_method_types);
247
    }
248
249
250
251
    /**
252
     * Gets an object of each payment method type, none of which are bound to a
253
     * payment method instance
254
     *
255
     * @param boolean $force_recheck whether to force re-checking for new payment method types
256
     * @return EE_PMT_Base[]
257
     */
258
    public function payment_method_types($force_recheck = false)
259
    {
260
        if ($force_recheck || empty($this->payment_method_objects)) {
261
            $this->maybe_register_payment_methods($force_recheck);
262
            foreach ($this->payment_method_type_names(true) as $classname) {
263
                if (! isset($this->payment_method_objects[$classname])) {
264
                    $this->payment_method_objects[$classname] = new $classname;
265
                }
266
            }
267
        }
268
        return $this->payment_method_objects;
269
    }
270
271
272
273
    /**
274
     * Changes the payment method's class name into the payment method type's name
275
     * (as used on the payment method's table's PMD_type field)
276
     *
277
     * @param string $classname
278
     * @return string
279
     */
280
    public function payment_method_type_sans_class_prefix($classname)
281
    {
282
        return str_replace('EE_PMT_', '', $classname);
283
    }
284
285
286
287
    /**
288
     * Does the opposite of payment-method_type_sans_prefix
289
     *
290
     * @param string $type
291
     * @return string
292
     */
293
    public function payment_method_class_from_type($type)
294
    {
295
        return 'EE_PMT_' . $type;
296
    }
297
298
299
300
    /**
301
     * Activates a payment method of the given type.
302
     *
303
     * @param string $payment_method_type the PMT_type; for EE_PMT_Invoice this would be 'Invoice'
304
     * @return EE_Payment_Method
305
     * @throws InvalidDataTypeException
306
     * @throws EE_Error
307
     */
308
    public function activate_a_payment_method_of_type($payment_method_type)
309
    {
310
        $this->maybe_register_payment_methods();
311
        $payment_method = EEM_Payment_Method::instance()->get_one_of_type($payment_method_type);
312
        if (! $payment_method instanceof EE_Payment_Method) {
313
            $pm_type_class = $this->payment_method_class_from_type($payment_method_type);
314
            if (class_exists($pm_type_class)) {
315
                /** @var $pm_type_obj EE_PMT_Base */
316
                $pm_type_obj = new $pm_type_class;
317
                $payment_method = EEM_Payment_Method::instance()->get_one_by_slug($pm_type_obj->system_name());
318
                if (! $payment_method) {
319
                    $payment_method = $this->create_payment_method_of_type($pm_type_obj);
320
                }
321
                $payment_method->set_type($payment_method_type);
322
                $this->initialize_payment_method($payment_method);
323
            } else {
324
                throw new EE_Error(
325
                    sprintf(
326
                        esc_html__(
327
                            'There is no payment method of type %1$s, so it could not be activated',
328
                            'event_espresso'
329
                        ),
330
                        $pm_type_class
331
                    )
332
                );
333
            }
334
        }
335
        $payment_method->set_active();
336
        $payment_method->save();
337
        /** @type EE_Message_Resource_Manager $message_resource_manager */
338
        //if this was the invoice message type, make sure users can view their invoices
339
        if ($payment_method->type() === 'Invoice'
340
            && (
341
                ! EEH_MSG_Template::is_mt_active('invoice')
342
            )
343
        ) {
344
            $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
345
            /** @type EE_Message_Resource_Manager $message_resource_manager */
346
            $message_resource_manager->ensure_message_type_is_active('invoice', 'html');
347
            new PersistentAdminNotice(
348
                'invoice_pm_requirements_notice',
349
                sprintf(
350
                    esc_html__(
351
                        'The Invoice payment method has been activated. It requires the %1$sinvoice message%2$s type to be active, so it was automatically activated for you.',
352
                        'event_espresso'
353
                    ),
354
                    '<a href="' . admin_url('admin.php?page=espresso_messages&action=settings') . '">',
355
                    '</a>'
356
                ),
357
                true
358
            );
359
        }
360
        return $payment_method;
361
    }
362
363
364
365
    /**
366
     * Creates a payment method of the specified type. Does not save it.
367
     *
368
     * @global WP_User    $current_user
369
     * @param EE_PMT_Base $pm_type_obj
370
     * @return EE_Payment_Method
371
     * @throws EE_Error
372
     */
373
    public function create_payment_method_of_type($pm_type_obj)
374
    {
375
        global $current_user;
376
        $payment_method = EE_Payment_Method::new_instance(
377
            array(
378
                'PMD_type'       => $pm_type_obj->system_name(),
379
                'PMD_name'       => $pm_type_obj->pretty_name(),
380
                'PMD_admin_name' => $pm_type_obj->pretty_name(),
381
                'PMD_slug'       => $pm_type_obj->system_name(),//automatically converted to slug
382
                'PMD_wp_user'    => $current_user->ID,
383
                'PMD_order'      => EEM_Payment_Method::instance()->count(
384
                        array(array('PMD_type' => array('!=', 'Admin_Only')))
385
                    ) * 10,
386
            )
387
        );
388
        return $payment_method;
389
    }
390
391
392
393
    /**
394
     * Sets the initial payment method properties (including extra meta)
395
     *
396
     * @param EE_Payment_Method $payment_method
397
     * @return EE_Payment_Method
398
     * @throws EE_Error
399
     */
400
    public function initialize_payment_method($payment_method)
401
    {
402
        $pm_type_obj = $payment_method->type_obj();
403
        $payment_method->set_description($pm_type_obj->default_description());
404
        if (! $payment_method->button_url()) {
405
            $payment_method->set_button_url($pm_type_obj->default_button_url());
406
        }
407
        //now add setup its default extra meta properties
408
        $extra_metas = $pm_type_obj->settings_form()->extra_meta_inputs();
409
        if (! empty($extra_metas)) {
410
            //verify the payment method has an ID before adding extra meta
411
            if (! $payment_method->ID()) {
412
                $payment_method->save();
413
            }
414
            foreach ($extra_metas as $meta_name => $input) {
415
                $payment_method->update_extra_meta($meta_name, $input->raw_value());
416
            }
417
        }
418
        return $payment_method;
419
    }
420
421
422
423
    /**
424
     * Makes sure the payment method is related to the specified payment method
425
     *
426
     * @deprecated in 4.9.40 because the currency payment method table is being deprecated
427
     * @param EE_Payment_Method $payment_method
428
     * @return EE_Payment_Method
429
     * @throws EE_Error
430
     */
431
    public function set_usable_currencies_on_payment_method($payment_method)
432
    {
433
        EE_Error::doing_it_wrong(
434
            'EE_Payment_Method_Manager::set_usable_currencies_on_payment_method',
435
            esc_html__(
436
                'We no longer define what currencies are usable by payment methods. Its not used nor efficient.',
437
                'event_espresso'
438
            ),
439
            '4.9.40'
440
        );
441
        return $payment_method;
442
    }
443
444
445
446
    /**
447
     * Deactivates a payment method of the given payment method slug.
448
     *
449
     * @param string $payment_method_slug The slug for the payment method to deactivate.
450
     * @return int count of rows updated.
451
     * @throws EE_Error
452
     */
453
    public function deactivate_payment_method($payment_method_slug)
454
    {
455
        EE_Log::instance()->log(
456
            __FILE__,
457
            __FUNCTION__,
458
            sprintf(
459
                esc_html__(
460
                    'Payment method with slug %1$s is being deactivated by site admin',
461
                    'event_espresso'
462
                ),
463
                $payment_method_slug
464
            ),
465
            'payment_method_change'
466
        );
467
        $count_updated = EEM_Payment_Method::instance()->update(
468
            array('PMD_scope' => array()),
469
            array(array('PMD_slug' => $payment_method_slug))
470
        );
471
        return $count_updated;
472
    }
473
474
475
476
    /**
477
     * initializes payment method access caps via EE_Capabilities::init_role_caps()
478
     * upon EE_Payment_Method_Manager construction
479
     *
480
     * @throws EE_Error
481
     * @throws DomainException
482
     */
483
    protected function initializePaymentMethodCaps()
484
    {
485
        // don't do this twice
486
        if ($this->payment_method_caps_initialized) {
487
            return;
488
        }
489
        EE_Capabilities::instance()->addCaps(
490
            $this->getPaymentMethodCaps()
491
        );
492
        $this->payment_method_caps_initialized = true;
493
    }
494
495
496
497
    /**
498
     * array  of dynamic payment method access caps.
499
     * at the time of writing, october 20 2014, these are the caps added:
500
     *  ee_payment_method_admin_only
501
     *  ee_payment_method_aim
502
     *  ee_payment_method_bank
503
     *  ee_payment_method_check
504
     *  ee_payment_method_invoice
505
     *  ee_payment_method_mijireh
506
     *  ee_payment_method_paypal_pro
507
     *  ee_payment_method_paypal_standard
508
     * Any other payment methods added to core or via addons will also get
509
     * their related capability automatically added too, so long as they are
510
     * registered properly using EE_Register_Payment_Method::register()
511
     *
512
     * @return array
513
     * @throws DomainException
514
     */
515
    protected function getPaymentMethodCaps()
516
    {
517
        $caps = array();
518
        foreach ($this->payment_method_type_names() as $payment_method_name) {
519
            $caps = $this->addPaymentMethodCap($payment_method_name,$caps);
520
        }
521
        return $caps;
522
    }
523
524
525
526
    /**
527
     * @param string $payment_method_name
528
     * @param array  $payment_method_caps
529
     * @param string $role
530
     * @return array
531
     * @throws DomainException
532
     */
533
    public function addPaymentMethodCap($payment_method_name, array $payment_method_caps, $role = 'administrator')
534
    {
535
        if (empty($payment_method_name)) {
536
            throw new DomainException(
537
                esc_html__(
538
                    'The name of a payment method must be specified to add capabilities.',
539
                    'event_espresso'
540
                )
541
            );
542
        }
543
        if (empty($role)) {
544
            throw new DomainException(
545
                sprintf(
546
                    esc_html__(
547
                        'No role was supplied while trying to add capabilities for the %1$s payment method.',
548
                        'event_espresso'
549
                    ),
550
                    $payment_method_name
551
                )
552
            );
553
        }
554
        if(! isset($payment_method_caps[$role])) {
555
            $payment_method_caps[$role] = array();
556
        }
557
        $payment_method_caps[$role][] = EE_Payment_Method_Manager::CAPABILITIES_PREFIX
558
                                                  . strtolower($payment_method_name);
559
        return $payment_method_caps;
560
    }
561
562
563
564
    /**
565
     * callback for FHEE__EE_Capabilities__init_role_caps__caps_map filter
566
     * to add dynamic payment method access caps when capabilities are reset
567
     * (or if that filter is called and PM caps are not already set)
568
     *
569
     * @param array $caps capabilities being filtered
570
     * @param bool  $reset
571
     * @return array
572
     * @throws DomainException
573
     */
574
    public function addPaymentMethodCapsDuringReset(array $caps, $reset = false)
575
    {
576
        if ($reset || ! $this->payment_method_caps_initialized) {
577
            $this->payment_method_caps_initialized = true;
578
            $caps = array_merge_recursive($caps, $this->getPaymentMethodCaps());
579
        }
580
        return $caps;
581
    }
582
583
584
585
    /**
586
     * @deprecated 4.9.42
587
     * @param $caps
588
     * @return mixed
589
     */
590
    public function add_payment_method_caps($caps)
591
    {
592
        return $caps;
593
    }
594
595
596
597
}
598