Completed
Push — develop ( 97a737...3a270c )
by Fabian
29s queued 18s
created

Client::chooseResponseHelper()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 4
c 1
b 0
f 0
nc 3
nop 1
dl 0
loc 9
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cakasim\Payone\Sdk\Api\Client;
6
7
use Cakasim\Payone\Sdk\Api\Client\ResponseHelper\BinaryResponseHelper;
8
use Cakasim\Payone\Sdk\Api\Client\ResponseHelper\DefaultResponseHelper;
9
use Cakasim\Payone\Sdk\Api\Client\ResponseHelper\JsonResponseHelper;
10
use Cakasim\Payone\Sdk\Api\Client\ResponseHelper\ResponseHelperInterface;
11
use Cakasim\Payone\Sdk\Api\Format\DecoderInterface;
12
use Cakasim\Payone\Sdk\Api\Format\EncoderExceptionInterface;
13
use Cakasim\Payone\Sdk\Api\Format\EncoderInterface;
14
use Cakasim\Payone\Sdk\Api\Message\Parameter\SubAccountIdAwareInterface;
15
use Cakasim\Payone\Sdk\Api\Message\RequestInterface;
16
use Cakasim\Payone\Sdk\Api\Message\ResponseInterface;
17
use Cakasim\Payone\Sdk\Config\ConfigExceptionInterface;
18
use Cakasim\Payone\Sdk\Config\ConfigInterface;
19
use Cakasim\Payone\Sdk\Sdk;
20
use Psr\Http\Client\ClientExceptionInterface as HttpClientExceptionInterface;
21
use Psr\Http\Client\ClientInterface as HttpClientInterface;
22
use Psr\Http\Message\RequestFactoryInterface as HttpRequestFactoryInterface;
23
use Psr\Http\Message\RequestInterface as HttpRequestInterface;
24
use Psr\Http\Message\ResponseInterface as HttpResponseInterface;
25
26
/**
27
 * The API client implementation.
28
 *
29
 * @author Fabian Böttcher <[email protected]>
30
 * @since 0.1.0
31
 */
32
class Client implements ClientInterface
33
{
34
    /**
35
     * @var ConfigInterface The SDK config.
36
     */
37
    protected $config;
38
39
    /**
40
     * @var HttpClientInterface The HTTP client.
41
     */
42
    protected $httpClient;
43
44
    /**
45
     * @var HttpRequestFactoryInterface The HTTP request factory.
46
     */
47
    protected $httpRequestFactory;
48
49
    /**
50
     * @var EncoderInterface The API format encoder.
51
     */
52
    protected $encoder;
53
54
    /**
55
     * @var DecoderInterface The API format decoder.
56
     */
57
    protected $decoder;
58
59
    /**
60
     * @var ResponseHelperInterface[] The response helpers of this client.
61
     */
62
    protected $responseHelpers = [];
63
64
    /**
65
     * Constructs the API client with dependencies.
66
     *
67
     * @param ConfigInterface $config The SDK config.
68
     * @param HttpClientInterface $httpClient The HTTP client.
69
     * @param HttpRequestFactoryInterface $httpRequestFactory The HTTP request factory.
70
     * @param EncoderInterface $encoder The API format encoder.
71
     * @param DecoderInterface $decoder The APi format decoder.
72
     */
73
    public function __construct(
74
        ConfigInterface $config,
75
        HttpClientInterface $httpClient,
76
        HttpRequestFactoryInterface $httpRequestFactory,
77
        EncoderInterface $encoder,
78
        DecoderInterface $decoder
79
    ) {
80
        $this->config = $config;
81
        $this->httpClient = $httpClient;
82
        $this->httpRequestFactory = $httpRequestFactory;
83
        $this->encoder = $encoder;
84
        $this->decoder = $decoder;
85
86
        $this->responseHelpers = [
87
            new JsonResponseHelper(),
88
            new BinaryResponseHelper($this->decoder),
89
            new DefaultResponseHelper($this->decoder),
90
        ];
91
    }
92
93
    /**
94
     * Returns the general request parameters that
95
     * will be applied to each request.
96
     *
97
     * @return array The general request parameter array.
98
     * @throws ConfigExceptionInterface If the required configuration is incomplete.
99
     */
100
    protected function makeGeneralRequestParameters(RequestInterface $request): array
101
    {
102
        $parameters = [
103
            'api_version'        => '3.11',
104
            'encoding'           => 'UTF-8',
105
            'mid'                => $this->config->get('api.merchant_id'),
106
            'portalid'           => $this->config->get('api.portal_id'),
107
            'key'                => $this->makeKeyHash(),
108
            'mode'               => $this->config->get('api.mode'),
109
            'solution_name'      => Sdk::API_SOLUTION_NAME,
110
            'solution_version'   => Sdk::API_SOLUTION_VERSION,
111
            'integrator_name'    => $this->config->get('api.integrator_name'),
112
            'integrator_version' => $this->config->get('api.integrator_version'),
113
        ];
114
115
        // Check if the request supports the sub account ID (aid) parameter.
116
        if ($request instanceof SubAccountIdAwareInterface) {
117
            $parameters['aid'] = $this->config->get('api.sub_account_id');
118
        }
119
120
        return $parameters;
121
    }
122
123
    /**
124
     * Returns the hash value of the API key.
125
     *
126
     * @return string The API key hash.
127
     * @throws ConfigExceptionInterface If the required configuration is incomplete.
128
     */
129
    protected function makeKeyHash(): string
130
    {
131
        return hash(
132
            $this->config->get('api.key_hash_type'),
133
            $this->config->get('api.key')
134
        );
135
    }
136
137
    /**
138
     * Chooses the proper response helper for the provided API response.
139
     *
140
     * @param ResponseInterface $response The API response.
141
     * @return ResponseHelperInterface The chosen response helper.
142
     * @throws ClientException If no proper response handler could be chosen.
143
     */
144
    protected function chooseResponseHelper(ResponseInterface $response): ResponseHelperInterface
145
    {
146
        foreach ($this->responseHelpers as $responseHelper) {
147
            if ($responseHelper->isResponsible($response)) {
148
                return $responseHelper;
149
            }
150
        }
151
152
        throw new ClientException("Cannot choose proper response helper.");
153
    }
154
155
    /**
156
     * @inheritDoc
157
     */
158
    public function sendRequest(RequestInterface $request, ResponseInterface $response): void
159
    {
160
        // Get proper response helper for provided API response.
161
        $responseHelper = $this->chooseResponseHelper($response);
162
163
        // Applies the general request parameters.
164
        $this->applyGeneralRequestParameters($request);
165
166
        // Make the parameter array from the request.
167
        $requestParameters = $request->makeParameterArray();
168
169
        // Create ready-to-send HTTP request from parameter array.
170
        $httpRequest = $this->createHttpRequest($requestParameters);
171
172
        // Apply any response helper HTTP request modifications.
173
        $httpRequest = $responseHelper->modifyHttpRequest($httpRequest);
174
175
        // Send the HTTP request to PAYONE.
176
        $httpResponse = $this->sendHttpRequest($httpRequest);
177
178
        // Make the response data from the HTTP response.
179
        $responseData = $responseHelper->makeResponseData($httpResponse);
180
181
        // Delegate further response data parsing to the provided API response.
182
        $response->parseResponseData($responseData);
183
    }
184
185
    /**
186
     * Applies the general request parameters to the API request.
187
     *
188
     * @param RequestInterface $request The API request to which the parameters will be applied.
189
     * @throws ClientException If the general parameters cannot be applied to the API request.
190
     */
191
    protected function applyGeneralRequestParameters(RequestInterface $request): void
192
    {
193
        try {
194
            // Apply general parameters to the request.
195
            $request->applyGeneralParameters($this->makeGeneralRequestParameters($request));
196
        } catch (ConfigExceptionInterface $e) {
197
            throw new ClientException("Cannot apply general request parameters.", 0, $e);
198
        }
199
    }
200
201
    /**
202
     * Creates the HTTP request.
203
     *
204
     * @param array $parameters The API parameters of the request.
205
     * @return HttpRequestInterface The created HTTP request.
206
     * @throws ClientException If the HTTP request cannot be created.
207
     */
208
    protected function createHttpRequest(array $parameters): HttpRequestInterface
209
    {
210
        try {
211
            // Get PAYONE API endpoint from config.
212
            $endpoint = $this->config->get('api.endpoint');
213
        } catch (ConfigExceptionInterface $e) {
214
            throw new ClientException("Cannot create HTTP request.", 0, $e);
215
        }
216
217
        // Create HTTP request via PSR-17 factory.
218
        $request = $this->httpRequestFactory->createRequest('POST', $endpoint)
219
            ->withHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
220
221
        try {
222
            // Encode the request parameters to API format.
223
            $body = $this->encoder->encode($parameters);
224
        } catch (EncoderExceptionInterface $e) {
225
            throw new ClientException("Cannot create HTTP request.", 0, $e);
226
        }
227
228
        // Write body contents to the request body and rewind the stream.
229
        $request->getBody()->write($body);
230
        $request->getBody()->rewind();
231
232
        return $request;
233
    }
234
235
    /**
236
     * Sends the HTTP request.
237
     *
238
     * @param HttpRequestInterface $request The HTTP request to send.
239
     * @return HttpResponseInterface The resulting HTTP response.
240
     * @throws ClientException If sending of the HTTP request fails.
241
     */
242
    protected function sendHttpRequest(HttpRequestInterface $request): HttpResponseInterface
243
    {
244
        try {
245
            return $this->httpClient->sendRequest($request);
246
        } catch (HttpClientExceptionInterface $e) {
247
            throw new ClientException("Failed to send API request.", 0, $e);
248
        }
249
    }
250
}
251