Gateway   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 237
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
eloc 81
dl 0
loc 237
rs 10
c 2
b 0
f 1
wmc 15

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A getloyToken() 0 3 1
A widgetPayload() 0 31 2
A widgetHtml() 0 35 2
A widgetCode() 0 20 3
A registerPaymentProvider() 0 7 1
A parseCallback() 0 5 1
A readCallbackBodyAndParse() 0 4 1
A validateCallback() 0 5 1
A transactionHash() 0 11 1
A merchantHash() 0 3 1
1
<?php declare(strict_types=1);
2
3
namespace Getloy;
4
5
use \Exception;
6
use Getloy\PaymentProviders;
7
use Getloy\CallbackDetails;
8
use Getloy\TransactionDetails\OrderDetails;
9
use Getloy\TransactionDetails\PayeeDetails;
10
11
/**
12
 * Gateway
13
 */
14
class Gateway
15
{
16
    protected $getloyToken;
17
    protected $requestOrigin;
18
    protected $paymentProviders = [];
19
20
    public function __construct(
21
        string $getloyToken,
22
        string $requestOrigin = 'getloy-integration-library-php v1.0.0'
23
    ) {
24
25
        $this->getloyToken = $getloyToken;
26
        $this->requestOrigin = $requestOrigin;
27
    }
28
29
    /**
30
     * Getter for the GetLoy token.
31
     *
32
     * @return string
33
     */
34
    public function getloyToken(): string
35
    {
36
        return $this->getloyToken;
37
    }
38
39
    /**
40
     * Register a payment provider
41
     * @param string $paymentMethod Payment method identifier.
42
     * @param array $config Configuration for the payment method.
43
     * @return boolean True if the registration completed successfully.
44
     * @throws Exception If the provided payment method is unsupported or the payment method
45
     *                   configuration is incomplete.
46
     */
47
    public function registerPaymentProvider(string $paymentMethod, array $config): bool
48
    {
49
        $this->paymentProviders[$paymentMethod] = PaymentProviders::paymentProviderFactory(
50
            $paymentMethod,
51
            $config
52
        );
53
        return true;
54
    }
55
56
    /**
57
     * Generates JavaScript code for the GetLoy widget.
58
     * @param array $options The widget options.
59
     * @return string Widget code (without enclosing <scipt> tag).
60
     * @throws Exception if $options array does not include the key `payload`.
61
     */
62
    protected function widgetCode(array $options): string
63
    {
64
        if (!array_key_exists('payload', $options)) {
65
            throw new Exception('Cannot create widget without payload option!');
66
        }
67
        $optionString = '';
68
        foreach ($options as $option => $value) {
69
            $optionString .= sprintf(
70
                "gl(%s, %s);",
71
                json_encode($option),
72
                json_encode($value)
73
            );
74
        }
75
        return sprintf(
76
            "!function(g,e,t,l,o,y){g.GetLoyPayments=t;g[t]||(g[t]=function(){"
77
            . "(g[t].q=g[t].q||[]).push(arguments)});g[t].l=+new Date;o=e.createElement(l);"
78
            . "y=e.getElementsByTagName(l)[0];o.src='https://some.getloy.com/getloy.js';"
79
            . "y.parentNode.insertBefore(o,y)}(window,document,'gl','script');"
80
            . "%s",
81
            $optionString
82
        );
83
    }
84
85
    /**
86
     * Generates HTML code for the GetLoy widget.
87
     * @param string $transactionId Payment transaction identifier.
88
     * @param string $paymentMethod Payment method identifier (see {@see \Getloy\PaymentProviders}).
89
     * @param OrderDetails $order Order details.
90
     * @param PayeeDetails $payee Payee details.
91
     * @param string $callbackUrl URL to call from the GetLoy backend to notify the custom web
92
     *                            application of status updates for the payment transaction.
93
     * @param string $successUrl URL to redirect the user to when the payment completed successfully
94
     *                           (optional).
95
     * @param string $cancelUrl URL to redirect the user to when the payment gets cancelled or fails
96
     *                          (optional).
97
     * @param string $paymentMethodVariant Payment method variant name (optional).
98
     * @param bool $addPopupContainer Whether to add the HTML element that will contain the payment
99
     *                                popup (default is true).
100
     * @return string Widget HTML code.
101
     * @throws Exception if the provided transaction details are invalid.
102
     */
103
    public function widgetHtml(
104
        string $transactionId,
105
        string $paymentMethod,
106
        OrderDetails $order,
107
        PayeeDetails $payee,
108
        string $callbackUrl,
109
        string $successUrl = null,
110
        string $cancelUrl = null,
111
        string $paymentMethodVariant = null,
112
        bool $addPopupContainer = true
113
    ): string {
114
115
        $payload = $this->widgetPayload(
116
            $transactionId,
117
            $paymentMethod,
118
            $order,
119
            $payee,
120
            $callbackUrl,
121
            $paymentMethodVariant
122
        );
123
        $widgetOptions = [
124
            'payload' => $payload,
125
            'success_callback' => sprintf(
126
                "function(){window.location='%s';}",
127
                addcslashes($successUrl, "'")
128
            ),
129
            'cancel_callback' => sprintf(
130
                "function(){window.location='%s';}",
131
                addcslashes($cancelUrl, "'")
132
            ),
133
        ];
134
        return sprintf(
135
            "%s<script>\n%s\n</script>",
136
            $addPopupContainer ? '<div class="getloy"></div>' : '',
137
            $this->widgetCode($widgetOptions)
138
        );
139
    }
140
141
    /**
142
     * Generate payload for GetLoy widget.
143
     *
144
     * @param string $transactionId Payment transaction identifier.
145
     * @param string $paymentMethod Payment method identifier.
146
     * @param OrderDetails $order Order details.
147
     * @param PayeeDetails $payee Payee details.
148
     * @param string $callbackUrl URL to call from the GetLoy backend to notify the custom web
149
     *                            application of status updates for the payment transaction.
150
     * @param string $paymentMethodVariant Payment method variant name (optional).
151
     * @return string Widget payload (JSON string)
152
     */
153
    public function widgetPayload(
154
        string $transactionId,
155
        string $paymentMethod,
156
        OrderDetails $order,
157
        PayeeDetails $payee,
158
        string $callbackUrl,
159
        string $paymentMethodVariant = null
160
    ): array {
161
162
        $payload = [
163
            'tid' => $transactionId,
164
            'provider' => $paymentMethod,
165
            'request_origin' => $this->requestOrigin,
166
            'callback' => $callbackUrl,
167
            'merchant_hash' => $this->merchantHash(),
168
            'auth_hash' => $this->transactionHash($transactionId, $order),
169
            'test_mode' => $this->paymentProviders[$paymentMethod]->get('testMode'),
170
            'payee' => $payee->payloadConfig(),
171
            'order' => $order->payloadConfig(),
172
            'payment_provider' => $this->paymentProviders[$paymentMethod]->paymentProviderPayload(
173
                $transactionId,
174
                $order,
175
                $payee,
176
                $callbackUrl,
177
                $paymentMethodVariant
178
            ),
179
        ];
180
        if ($paymentMethodVariant) {
181
            $payload['provider_variant'] = $paymentMethodVariant;
182
        }
183
        return $payload;
184
    }
185
186
    /**
187
     * Parse and validate the body of a callback request.
188
     *
189
     * @param string $jsonCallback
190
     * @return CallbackDetails
191
     */
192
    public function parseCallback(string $jsonCallback): CallbackDetails
193
    {
194
        $callbackDetails = new CallbackDetails($this);
195
        $callbackDetails->parseCallback($jsonCallback);
196
        return $callbackDetails;
197
    }
198
199
    /**
200
     * Validate a callback request.
201
     *
202
     * @param array $callbackBody
203
     * @return CallbackDetails
204
     */
205
    public function validateCallback(array $callbackBody): CallbackDetails
206
    {
207
        $callbackDetails = new CallbackDetails($this);
208
        $callbackDetails->validateCallback($callbackBody);
209
        return $callbackDetails;
210
    }
211
212
    /**
213
     * Read callback body from php://input, parse and validate the  request.
214
     *
215
     * @return CallbackDetails
216
     */
217
    public function readCallbackBodyAndParse(): CallbackDetails
218
    {
219
        $callbackBody = file_get_contents('php://input');
220
        return $this->parseCallback($callbackBody);
221
    }
222
223
    /**
224
     * Compute the merchant hash.
225
     *
226
     * @return string Hash value (hex string).
227
     */
228
    protected function merchantHash(): string
229
    {
230
        return hash_hmac('sha512', $this->getloyToken, $this->getloyToken);
231
    }
232
233
    /**
234
     * Compute the transaction authentication hash.
235
     *
236
     * @param string $transactionId Payment transaction identifier.
237
     * @param OrderDetails $order Order details.
238
     * @return string Hash value (hex string).
239
     */
240
    protected function transactionHash(string $transactionId, OrderDetails $order): string
241
    {
242
        return hash_hmac(
243
            'sha512',
244
            sprintf(
245
                '%s%s%.2f',
246
                $this->getloyToken,
247
                $transactionId,
248
                $order->totalAmount()
249
            ),
250
            $this->getloyToken
251
        );
252
    }
253
}
254