ErrorHandler   A
last analyzed

Complexity

Total Complexity 10

Size/Duplication

Total Lines 148
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 87.5%

Importance

Changes 0
Metric Value
wmc 10
lcom 1
cbo 6
dl 0
loc 148
ccs 21
cts 24
cp 0.875
rs 10
c 0
b 0
f 0

2 Methods

Rating   Name   Duplication   Size   Complexity  
B handle() 0 35 7
A getExceptionForStatusCode() 0 11 3
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This software may be modified and distributed under the terms
7
 * of the MIT license. See the LICENSE file for details.
8
 */
9
10
namespace Shapin\Stripe;
11
12
use Shapin\Stripe\Exception\Domain as DomainExceptions;
13
use Shapin\Stripe\Exception\DomainException;
14
use Symfony\Contracts\HttpClient\ResponseInterface;
15
16
final class ErrorHandler
17
{
18
    public static $errorCodes = [
19
        'account_already_exists' => DomainExceptions\BadRequestException::class,
20
        'account_country_invalid_address' => DomainExceptions\BadRequestException::class,
21
        'account_invalid' => DomainExceptions\BadRequestException::class,
22
        'account_number_invalid' => DomainExceptions\BadRequestException::class,
23
        'alipay_upgrade_required' => DomainExceptions\BadRequestException::class,
24
        'amount_too_large' => DomainExceptions\BadRequestException::class,
25
        'amount_too_small' => DomainExceptions\BadRequestException::class,
26
        'api_key_expired' => DomainExceptions\BadRequestException::class,
27
        'balance_insufficient' => DomainExceptions\BadRequestException::class,
28
        'bank_account_exists' => DomainExceptions\BadRequestException::class,
29
        'bank_account_unusable' => DomainExceptions\BadRequestException::class,
30
        'bank_account_unverified' => DomainExceptions\BadRequestException::class,
31
        'bitcoin_upgrade_required' => DomainExceptions\BadRequestException::class,
32
        'charge_already_captured' => DomainExceptions\BadRequestException::class,
33
        'charge_already_refunded' => DomainExceptions\ChargeAlreadyRefundedException::class,
34
        'charge_disputed' => DomainExceptions\BadRequestException::class,
35
        'charge_exceeds_source_limit' => DomainExceptions\BadRequestException::class,
36
        'charge_expired_for_capture' => DomainExceptions\BadRequestException::class,
37
        'country_unsupported' => DomainExceptions\BadRequestException::class,
38
        'coupon_expired' => DomainExceptions\BadRequestException::class,
39
        'customer_max_subscriptions' => DomainExceptions\BadRequestException::class,
40
        'email_invalid' => DomainExceptions\BadRequestException::class,
41
        'expired_card' => DomainExceptions\BadRequestException::class,
42
        'idempotency_key_in_use' => DomainExceptions\BadRequestException::class,
43
        'incorrect_address' => DomainExceptions\BadRequestException::class,
44
        'incorrect_cvc' => DomainExceptions\IncorrectCvcException::class,
45
        'incorrect_number' => DomainExceptions\IncorrectNumberException::class,
46
        'incorrect_zip' => DomainExceptions\BadRequestException::class,
47
        'instant_payouts_unsupported' => DomainExceptions\BadRequestException::class,
48
        'invalid_card_type' => DomainExceptions\BadRequestException::class,
49
        'invalid_charge_amount' => DomainExceptions\BadRequestException::class,
50
        'invalid_cvc' => DomainExceptions\BadRequestException::class,
51
        'invalid_expiry_month' => DomainExceptions\BadRequestException::class,
52
        'invalid_expiry_year' => DomainExceptions\BadRequestException::class,
53
        'invalid_number' => DomainExceptions\BadRequestException::class,
54
        'invalid_source_usage' => DomainExceptions\BadRequestException::class,
55
        'invoice_no_customer_line_items' => DomainExceptions\BadRequestException::class,
56
        'invoice_no_subscription_line_items' => DomainExceptions\BadRequestException::class,
57
        'invoice_not_editable' => DomainExceptions\BadRequestException::class,
58
        'invoice_upcoming_none' => DomainExceptions\BadRequestException::class,
59
        'livemode_mismatch' => DomainExceptions\BadRequestException::class,
60
        'missing' => DomainExceptions\BadRequestException::class,
61
        'not_allowed_on_standard_account' => DomainExceptions\BadRequestException::class,
62
        'order_creation_failed' => DomainExceptions\BadRequestException::class,
63
        'order_required_settings' => DomainExceptions\BadRequestException::class,
64
        'order_status_invalid' => DomainExceptions\BadRequestException::class,
65
        'order_upstream_timeout' => DomainExceptions\BadRequestException::class,
66
        'out_of_inventory' => DomainExceptions\BadRequestException::class,
67
        'parameter_invalid_empty' => DomainExceptions\BadRequestException::class,
68
        'parameter_invalid_integer' => DomainExceptions\BadRequestException::class,
69
        'parameter_invalid_string_blank' => DomainExceptions\BadRequestException::class,
70
        'parameter_invalid_string_empty' => DomainExceptions\BadRequestException::class,
71
        'parameter_missing' => DomainExceptions\BadRequestException::class,
72
        'parameter_unknown' => DomainExceptions\BadRequestException::class,
73
        'parameters_exclusive' => DomainExceptions\BadRequestException::class,
74
        'payment_intent_authentication_failure' => DomainExceptions\BadRequestException::class,
75
        'payment_intent_incompatible_payment_method' => DomainExceptions\BadRequestException::class,
76
        'payment_intent_invalid_parameter' => DomainExceptions\BadRequestException::class,
77
        'payment_intent_payment_attempt_failed' => DomainExceptions\BadRequestException::class,
78
        'payment_intent_unexpected_state' => DomainExceptions\BadRequestException::class,
79
        'payment_method_unactivated' => DomainExceptions\BadRequestException::class,
80
        'payment_method_unexpected_state' => DomainExceptions\BadRequestException::class,
81
        'payouts_not_allowed' => DomainExceptions\BadRequestException::class,
82
        'platform_api_key_expired' => DomainExceptions\BadRequestException::class,
83
        'postal_code_invalid' => DomainExceptions\BadRequestException::class,
84
        'processing_error' => DomainExceptions\BadRequestException::class,
85
        'product_inactive' => DomainExceptions\BadRequestException::class,
86
        'rate_limit' => DomainExceptions\BadRequestException::class,
87
        'resource_already_exists' => DomainExceptions\ResourceAlreadyExistsException::class,
88
        'resource_missing' => DomainExceptions\BadRequestException::class,
89
        'routing_number_invalid' => DomainExceptions\BadRequestException::class,
90
        'secret_key_required' => DomainExceptions\BadRequestException::class,
91
        'sepa_unsupported_account' => DomainExceptions\BadRequestException::class,
92
        'shipping_calculation_failed' => DomainExceptions\BadRequestException::class,
93
        'sku_inactive' => DomainExceptions\BadRequestException::class,
94
        'state_unsupported' => DomainExceptions\BadRequestException::class,
95
        'tax_id_invalid' => DomainExceptions\BadRequestException::class,
96
        'taxes_calculation_failed' => DomainExceptions\BadRequestException::class,
97
        'testmode_charges_only' => DomainExceptions\BadRequestException::class,
98
        'tls_version_unsupported' => DomainExceptions\BadRequestException::class,
99
        'token_already_used' => DomainExceptions\BadRequestException::class,
100
        'token_in_use' => DomainExceptions\BadRequestException::class,
101
        'transfers_not_allowed' => DomainExceptions\BadRequestException::class,
102
        'upstream_order_creation_failed' => DomainExceptions\BadRequestException::class,
103
        'url_invalid' => DomainExceptions\BadRequestException::class,
104
    ];
105
106
    public static $cardDeclinedCodes = [
107
        'card_not_supported' => DomainExceptions\CardDeclined\CardNotSupportedException::class,
108
        'expired_card' => DomainExceptions\CardDeclined\ExpiredCardException::class,
109
        'incorrect_cvc' => DomainExceptions\CardDeclined\IncorrectCvcException::class,
110
        'incorrect_number' => DomainExceptions\CardDeclined\IncorrectNumberException::class,
111
        'invalid_cvc' => DomainExceptions\CardDeclined\IncorrectCvcException::class,
112
        'invalid_number' => DomainExceptions\CardDeclined\IncorrectNumberException::class,
113
        'insufficient_funds' => DomainExceptions\CardDeclined\InsufficientFundsException::class,
114
    ];
115
116 96
    public function handle(ResponseInterface $response): void
117
    {
118 96
        $data = json_decode($response->getContent(false), true);
119
120 96
        if (\JSON_ERROR_NONE !== json_last_error()) {
121
            throw $this->getExceptionForStatusCode($response);
122
        }
123
124 96
        if (!\array_key_exists('error', $data)) {
125
            throw $this->getExceptionForStatusCode($response);
126
        }
127
128 96
        if (!\array_key_exists('code', $data['error'])) {
129 3
            throw $this->getExceptionForStatusCode($response);
130
        }
131
132 93
        $errorCode = $data['error']['code'];
133
134 93
        if (\array_key_exists($errorCode, self::$errorCodes)) {
135 85
            throw new self::$errorCodes[$errorCode]($response);
136
        }
137
138
        // We have a lot of decline codes for "card_declined" errors.
139 8
        if ('card_declined' === $errorCode) {
140 8
            $declineCode = $data['error']['decline_code'];
141
142 8
            if (\array_key_exists($declineCode, self::$cardDeclinedCodes)) {
143 7
                throw new self::$cardDeclinedCodes[$declineCode]($response);
144
            }
145
146 1
            throw new DomainExceptions\CardDeclinedException($response);
147
        }
148
149
        throw $this->getExceptionForStatusCode($response);
150
    }
151
152 3
    private function getExceptionForStatusCode(ResponseInterface $response): DomainException
153
    {
154 3
        switch ($response->getStatusCode()) {
155 3
            case 400:
156 1
                return new DomainExceptions\BadRequestException($response);
157 2
            case 404:
158 1
                return new DomainExceptions\NotFoundException();
159
            default:
160 1
                return new DomainExceptions\UnknownErrorException($response);
161
        }
162
    }
163
}
164