Passed
Push — main ( 4dc4a3...97513a )
by Stas
14:40 queued 04:40
created

Validator::wrapResponse()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 21
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 9
c 1
b 0
f 0
nc 4
nop 2
dl 0
loc 21
rs 9.9666
1
<?php
2
3
namespace Huawei\IAP;
4
5
use GuzzleHttp\Client;
6
use GuzzleHttp\Exception\BadResponseException;
7
use Psr\Http\Message\ResponseInterface;
8
use Huawei\IAP\Exception\InvalidValidationResponseException;
9
use Huawei\IAP\Request\AbstractVerificationRequest;
10
use Huawei\IAP\Request\OrderVerificationRequest;
11
use Huawei\IAP\Request\SubscriptionVerificationRequest;
12
use Huawei\IAP\Response\OrderResponse;
13
use Huawei\IAP\Response\SubscriptionResponse;
14
15
class Validator
16
{
17
    const TYPE_SUBSCRIPTION = 'subscription';
18
    const TYPE_ORDER = 'order';
19
20
    /** @var \Huawei\IAP\AuthorizationStorage */
21
    protected $authorizationStorage;
22
    /** @var \Huawei\IAP\StoreSiteSelector */
23
    protected $siteSelector;
24
25
    protected function getClientConfig()
26
    {
27
        return ['timeout' => 5];
28
    }
29
30
    public function __construct()
31
    {
32
        $this->authorizationStorage = new AuthorizationStorage();
33
        $this->siteSelector = new StoreSiteSelector();
34
    }
35
36
    /**
37
     * @param AuthorizationStorage $storage
38
     */
39
    public function setAuthorizationStorage(AuthorizationStorage $storage)
40
    {
41
        $this->authorizationStorage = $storage;
42
    }
43
44
    protected function getClient(string $type, ?string $country = null, ?int $accountFlag = null)
45
    {
46
        $choice = $this->siteSelector->selectSite($type, $country, $accountFlag);
47
        $baseUrl = $choice->getSiteUrl();
48
49
        $config = array_merge(['base_uri' => $baseUrl], $this->getClientConfig());
50
51
        return new Client($config);
52
    }
53
54
    protected function getAuthorizationBuilder()
55
    {
56
        return new AuthorizationBuilder();
57
    }
58
59
    /**
60
     * @param AuthorizationCredentials $credentials
61
     * @param PurchaseData $purchaseData
62
     * @return OrderResponse|SubscriptionResponse
63
     */
64
    public function validate(AuthorizationCredentials $credentials, PurchaseData $purchaseData)
65
    {
66
        try {
67
            $request = $this->makeRequest($purchaseData, $credentials);
68
            $response = $request->do();
69
        } catch (BadResponseException $ex) {
70
            $errorConnectedWithAccess = $ex->getCode() === 401;
71
            $request = $this->makeRequest($purchaseData, $credentials, $errorConnectedWithAccess);
72
            $response = $request->do();
73
        }
74
75
        return $this->wrapResponse($response, $request);
76
    }
77
78
    /**
79
     * @param PurchaseData $purchaseData
80
     * @return SubscriptionVerificationRequest
81
     */
82
    protected function createSubscriptionVerificationRequest(PurchaseData $purchaseData): SubscriptionVerificationRequest
83
    {
84
        $type = $purchaseData->getType();
85
        $client = $this->getClient($type);
86
87
        return new SubscriptionVerificationRequest($client, $purchaseData);
88
    }
89
90
    /**
91
     * @param PurchaseData $purchaseData
92
     * @return OrderVerificationRequest
93
     */
94
    protected function createOrderVerificationRequest(PurchaseData $purchaseData): OrderVerificationRequest
95
    {
96
        $type = $purchaseData->getType();
97
        $client = $this->getClient($type);
98
99
        return new OrderVerificationRequest($client, $purchaseData);
100
    }
101
102
    /**
103
     * @param PurchaseData             $purchaseData
104
     * @param AuthorizationCredentials $credentials
105
     * @param bool                     $forceAuthorization
106
     *
107
     * @return AbstractVerificationRequest
108
     */
109
    protected function makeRequest(
110
        PurchaseData $purchaseData,
111
        AuthorizationCredentials $credentials,
112
        bool $forceAuthorization = false
113
    ): AbstractVerificationRequest
114
    {
115
        $type = $purchaseData->getType();
116
117
        if ($type === self::TYPE_SUBSCRIPTION) {
118
            $request = $this->createSubscriptionVerificationRequest($purchaseData);
119
        } elseif ($type === self::TYPE_ORDER) {
120
            $request = $this->createOrderVerificationRequest($purchaseData);
121
        } else {
122
            throw new \RuntimeException('Unsupported purchase type for verification');
123
        }
124
125
        $headers = [
126
            'Authorization' => $this->buildAuthHeader($credentials, $forceAuthorization),
127
        ];
128
129
        $request->setHeaders($headers);
130
131
        return $request;
132
    }
133
134
    protected function buildAuthHeader(
135
        AuthorizationCredentials $credentials,
136
        bool $forceAuthorization
137
    ): string
138
    {
139
        $authorizationBuilder = $this->getAuthorizationBuilder();
140
141
        $accessToken = $this->authorizationStorage->fetch($credentials);
142
143
        if ($forceAuthorization || $accessToken === null) {
144
            $accessToken = $authorizationBuilder->getAccessToken($credentials);
145
            $this->authorizationStorage->save($credentials, $accessToken);
146
        }
147
148
        return $authorizationBuilder->buildAuthorizationHeader($accessToken);
149
    }
150
151
    protected function wrapResponse(
152
        ResponseInterface $response,
153
        AbstractVerificationRequest $request
154
    )
155
    {
156
        $body = $response->getBody()->getContents();
157
        $json = \json_decode($body, true);
158
159
        if (\json_last_error() !== JSON_ERROR_NONE) {
160
            throw new InvalidValidationResponseException();
161
        }
162
163
        if ($request instanceof SubscriptionVerificationRequest) {
164
            return new SubscriptionResponse($json);
165
        }
166
167
        if ($request instanceof OrderVerificationRequest) {
168
            return new OrderResponse($json);
169
        }
170
171
        throw new \RuntimeException('Unsupported verification request');
172
    }
173
174
}
175