PluginProbe
MONEI Payments for WooCommerce / 7.3.1
MONEI Payments for WooCommerce v7.3.1
7.3.3 7.3.2 7.3.1 7.3.0 7.2.4 7.2.3 7.2.2 7.2.0 7.2.1 7.1.3 2.1.0 3.0.0 3.1.0 3.1.1 4.0.0 4.1.0 4.1.1 4.2.0 4.2.1 5.0 5.1.0 5.1.1 5.1.2 5.2.2 5.2.3 All 87 releases
monei / src / Repositories / PaymentMethodsRepository.php

PaymentMethodsRepository.php in MONEI Payments for WooCommerce 7.3.1, at src/Repositories/PaymentMethodsRepository.php

98 lines 3.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Monei\Repositories;
4
5 use Monei\MoneiClient;
6 use Exception;
7
8 class PaymentMethodsRepository implements PaymentMethodsRepositoryInterface {
9 /**
10 * Cached marker for "the API said no". Distinct from an empty array so the
11 * cache can hold it: an empty array is falsy and would be re-fetched.
12 */
13 private const UNAVAILABLE = array(
14 'paymentMethods' => array(),
15 'metadata' => array(),
16 );
17
18 private $accountId;
19 private MoneiClient $moneiClient;
20
21 public function __construct( string $accountId, MoneiClient $moneiClient ) {
22 $this->accountId = $accountId;
23 $this->moneiClient = $moneiClient;
24 }
25
26 /**
27 * Fetch payment methods from the API.
28 */
29 private function fetchFromAPI(): ?array {
30 // The account id no longer reaches the API — getAllowed() derives the account
31 // from the API key. It still gates the call because it is what separates the
32 // test cache from the live one, and because an unset one means the plugin is
33 // not configured yet.
34 if ( ! $this->accountId ) {
35 return null;
36 }
37 try {
38 // /allowed-payment-methods, the API key authenticated replacement for the
39 // deprecated /payment-methods. Amount, currency and country are left out on
40 // purpose: this repository is a container singleton that answers admin
41 // screens as well as the checkout, so it has no one cart to describe.
42 $response = $this->moneiClient->paymentMethods->getAllowed();
43 } catch ( Exception $e ) {
44 $response = null;
45 }
46
47 return $response ? json_decode( $response, true ) : array();
48 }
49
50 /**
51 * Get payment methods (fetch from transient or API).
52 */
53 public function getPaymentMethods(): array {
54 $transientKey = $this->generateTransientKey( $this->accountId );
55 $data = get_transient( $transientKey );
56
57 if ( ! $data ) {
58 $data = $this->fetchFromAPI();
59 if ( $data ) {
60 set_transient( $transientKey, $data, 30 );
61 set_transient( $this->fallbackKey( $transientKey ), $data, HOUR_IN_SECONDS );
62 } else {
63 // An empty answer marks every gateway unavailable, which takes
64 // the payment methods off the checkout. The 30 second cache
65 // makes that one failed call away at any moment, so fall back
66 // to the last answer that worked.
67 $data = get_transient( $this->fallbackKey( $transientKey ) );
68 if ( ! $data ) {
69 // No answer has ever worked: a wrong or missing API key. An
70 // empty array is falsy, so it never reached the cache and
71 // every checkout render repeated the failing call. One
72 // store did this 15 times a second for a week.
73 $data = self::UNAVAILABLE;
74 }
75 // Without this every request during an outage repeats the
76 // failing call.
77 set_transient( $transientKey, $data, 30 );
78 }
79 }
80
81 return $data === self::UNAVAILABLE ? array() : ( $data ?: array() );
82 }
83
84 /**
85 * Generate a transient key.
86 */
87 private function generateTransientKey( string $key ): string {
88 return 'payment_methods_' . md5( $key );
89 }
90
91 /**
92 * Key of the longer lived copy used when the API call fails.
93 */
94 private function fallbackKey( string $transientKey ): string {
95 return $transientKey . '_last_ok';
96 }
97 }
98