Completed
Push — master ( ba1824...14a9f3 )
by Olivier
01:37
created

ErrorHandler::handle()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 7.2694

Importance

Changes 0
Metric Value
dl 0
loc 35
ccs 14
cts 17
cp 0.8235
rs 8.4266
c 0
b 0
f 0
cc 7
nc 7
nop 1
crap 7.2694
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
        'incorrect_cvc' => DomainExceptions\CardDeclined\IncorrectCvcException::class,
108
        'incorrect_number' => DomainExceptions\CardDeclined\IncorrectNumberException::class,
109
        'invalid_cvc' => DomainExceptions\CardDeclined\IncorrectCvcException::class,
110
        'invalid_number' => DomainExceptions\CardDeclined\IncorrectNumberException::class,
111
        'insufficient_funds' =>  DomainExceptions\CardDeclined\InsufficientFundsException::class,
112
    ];
113
114 94
    public function handle(ResponseInterface $response): void
115
    {
116 94
        $data = json_decode($response->getContent(false), true);
117
118 94
        if (\JSON_ERROR_NONE !== json_last_error()) {
119
            throw $this->getExceptionForStatusCode($response);
120
        }
121
122 94
        if (!\array_key_exists('error', $data)) {
123
            throw $this->getExceptionForStatusCode($response);
124
        }
125
126 94
        if (!\array_key_exists('code', $data['error'])) {
127 3
            throw $this->getExceptionForStatusCode($response);
128
        }
129
130 91
        $errorCode = $data['error']['code'];
131
132 91
        if (\array_key_exists($errorCode, self::$errorCodes)) {
133 85
            throw new self::$errorCodes[$errorCode]($response);
134
        }
135
136
        // We have a lot of decline codes for "card_declined" errors.
137 6
        if ('card_declined' === $errorCode) {
138 6
            $declineCode = $data['error']['decline_code'];
139
140 6
            if (\array_key_exists($declineCode, self::$cardDeclinedCodes)) {
141 5
                throw new self::$cardDeclinedCodes[$declineCode]($response);
142
            }
143
144 1
            throw new DomainExceptions\CardDeclinedException($response);
145
        }
146
147
        throw $this->getExceptionForStatusCode($response);
148
    }
149
150 3
    private function getExceptionForStatusCode(ResponseInterface $response): DomainException
151
    {
152 3
        switch ($response->getStatusCode()) {
153 3
            case 400:
154 1
                return new DomainExceptions\BadRequestException($response);
155 2
            case 404:
156 1
                return new DomainExceptions\NotFoundException();
157
            default:
158 1
                return new DomainExceptions\UnknownErrorException($response);
159
        }
160
    }
161
}
162