Client::prepareOptions()   A
last analyzed

Complexity

Conditions 5
Paths 16

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 8
dl 0
loc 13
c 0
b 0
f 0
rs 9.6111
cc 5
nc 16
nop 1
1
<?php
2
3
namespace Dokobit\Gateway;
4
5
use Dokobit\Gateway\Http\ClientInterface;
6
use Dokobit\Gateway\Http\GuzzleClientAdapter;
7
use Dokobit\Gateway\Query\QueryInterface;
8
use Dokobit\Gateway\Result\ResultInterface;
9
use Psr\Log\LoggerInterface;
10
use Symfony\Component\Validator\Validation;
11
use Symfony\Component\Validator\Validator\ValidatorInterface;
12
use GuzzleHttp\HandlerStack;
13
use GuzzleHttp\Middleware;
14
use GuzzleHttp\MessageFormatter;
15
16
/**
17
 * Dokobit Gateway client
18
 */
19
class Client
20
{
21
    /** @var boolean use sandbox */
22
    private $sandbox = false;
23
24
    /** @var string API access key provided by Dokobit */
25
    private $apiKey = null;
26
27
    /** @var string production API URL */
28
    private $url = 'https://gateway.dokobit.com';
29
30
    /** @var string sandbox mode API URL. Used if $sandbox is true */
31
    private $sandboxUrl = 'https://gateway-sandbox.dokobit.com';
32
33
    /** @var ClientInterface HTTP client */
34
    private $client;
35
36
    /** @var ResponseMapperInterface response to result object mapper */
37
    private $responseMapper;
38
39
    /** @var ValidatorInterface Query validator */
40
    private $validator;
41
    /**
42
     * @param ClientInterface $client
43
     * @param ResponseMapperInterface $responseMapper
44
     * @param ValidatorInterface $validator
45
     * @param array $options
46
     * @return self
47
     */
48
    public function __construct(
49
        ClientInterface $client,
50
        ResponseMapperInterface $responseMapper,
51
        ValidatorInterface $validator,
52
        array $options = []
53
    ) {
54
        $this->validateOptions($options);
55
        $this->prepareOptions($options);
56
57
        $this->client = $client;
58
        $this->responseMapper = $responseMapper;
59
        $this->validator = $validator;
60
    }
61
62
63
    /**
64
     * Public factory method to create instance of Client.
65
     *
66
     * @param array $options Available properties: [
67
     *     'apiKey' => 'xxxxxx',
68
     *     'sandbox' => true,
69
     *     'url' => 'https://gateway.isign.io',
70
     *     'sandboxUrl' => 'https://gateway-sandbox.dokobit.com',
71
     * ]
72
     * @param LoggerInterface|null $logger Logger used to log
73
     *     messages. Pass a LoggerInterface to use a PSR-3 logger.
74
     *     Pass null or leave empty to disable logging.
75
     * @return self
76
     */
77
    public static function create(array $options = [], LoggerInterface $logger = null)
78
    {
79
        $client = new \GuzzleHttp\Client();
80
81
        if ($logger !== null) {
82
            $stack = HandlerStack::create();
83
            $stack->push(
84
                Middleware::log(
85
                    $logger,
86
                    new MessageFormatter()
87
                )
88
            );
89
90
            $client = new \GuzzleHttp\Client(
91
                [
92
                    'handler' => $stack,
93
                ]
94
            );
95
        }
96
97
        return new self(
98
            new GuzzleClientAdapter($client),
99
            new ResponseMapper(),
100
            Validation::createValidator(),
101
            $options
102
        );
103
    }
104
105
    /**
106
     * Get result by given query object
107
     * @param QueryInterface $query
108
     * @return ResultInterface
109
     */
110
    public function get(QueryInterface $query): ResultInterface
111
    {
112
        $this->validate($query);
113
        $fields = $query->getFields();
114
115
        return $this->responseMapper->map(
116
            $this->request(
117
                $query->getMethod(),
118
                $this->getFullMethodUrl($query->getAction()),
119
                $fields
120
            ),
121
            $query->createResult()
122
        );
123
    }
124
125
    /**
126
     * Check if sandbox enabled
127
     * @return boolean
128
     */
129
    public function isSandbox()
130
    {
131
        return $this->sandbox;
132
    }
133
134
    /**
135
     * Get API access key
136
     * @return string
137
     */
138
    public function getApiKey()
139
    {
140
        return $this->apiKey;
141
    }
142
143
    /**
144
     * Set API access key
145
     * @var $apiKey string
146
     */
147
    public function setApiKey($apiKey)
148
    {
149
        return $this->apiKey = $apiKey;
150
    }
151
152
    /**
153
     * Get production API URL
154
     * @return string
155
     */
156
    public function getUrl()
157
    {
158
        return $this->url;
159
    }
160
161
    /**
162
     * Get sandbox API URL
163
     * @return string
164
     */
165
    public function getSandboxUrl()
166
    {
167
        return $this->sandboxUrl;
168
    }
169
170
    /**
171
     * Get the base URL used for all calls.
172
     */
173
    public function getBaseUrl(): string
174
    {
175
        return $this->sandbox ? $this->sandboxUrl : $this->url;
176
    }
177
178
    /**
179
     * Get full API method URL by given action and token.
180
     * Checks if sandbox is enabled, then uses $sandboxUrl, otherwise
181
     * uses $url
182
     * @param string $action
183
     * @return string
184
     */
185
    public function getFullMethodUrl(string $action)
186
    {
187
        return $this->getBaseUrl() . '/api/' . $action . '.json';
188
    }
189
190
    /**
191
     * Get the URL for viewing uploaded file in a frame/modal.
192
     *
193
     * @param string $token File token returned by the Upload action.
194
     * @return string
195
     */
196
    public function getOpenUrl(string $token): string
197
    {
198
        $url = $this->getBaseUrl();
199
200
        return $url . '/open/' . $token;
201
    }
202
203
    /**
204
     * Get the URL for user to sign the file in a frame/modal.
205
     *
206
     * @param string $token File token returned by the Upload action.
207
     * @param string $accessToken User access token returned by the Addsigner action.
208
     * @return string
209
     */
210
    public function getSigningUrl(string $token, string $accessToken): string
211
    {
212
        $url = $this->getBaseUrl();
213
214
        return $url . '/signing/' . $token . '?access_token=' . $accessToken;
215
    }
216
217
    /**
218
     * Get the URL for signing multiple documents in a frame/modal with one action using a Smart Card.
219
     *
220
     * @param string $token Batch signing token returned by the Createbatch action.
221
     * @return string
222
     */
223
    public function getBatchSigningUrl(string $token): string
224
    {
225
        $url = $this->getBaseUrl();
226
227
        return $url . '/signing/batch/' . $token;
228
    }
229
230
    /**
231
     * Get the URL for signing multiple documents in a frame/modal in sequence.
232
     *
233
     * @param string $token Batch signing token returned by the Createbatch action.
234
     */
235
    public function getSequenceSigningUrl(string $token): string
236
    {
237
        $url = $this->getBaseUrl();
238
239
        return $url . '/signing/sequence/' . $token;
240
    }
241
242
    /**
243
     * Download signed file from a given URL and place it in the specified path.
244
     *
245
     * @param string $url URL to download.
246
     * @param string $path Path to download the file to.
247
     * @param bool $sendAccessToken Set this to false if you do not want access token appended to the URL automatically.
248
     *             Defaults to true.
249
     */
250
    public function downloadFile(
251
        string $url,
252
        string $path,
253
        bool $sendAccessToken = true
254
    ): void {
255
        if ($sendAccessToken) {
256
            $url .= '?access_token=' . $this->apiKey;
257
        }
258
259
        $this->client->requestBody(QueryInterface::GET, $url, ['save_to' => $path]);
260
    }
261
262
    /**
263
     * Handle request options and perform HTTP request using HTTP client.
264
     * @param string $method
265
     * @param string $url
266
     * @param array $fields
267
     * @return array|null
268
     */
269
    private function request(string $method, string $url, array $fields): ?array
270
    {
271
272
        $options = [
273
            'query' => [
274
                'access_token' => $this->getApiKey()
275
            ],
276
            'json' => $fields,
277
        ];
278
279
        return $this->client->requestJson($method, $url, $options);
280
    }
281
282
    /**
283
     * Read options from array and set values as object properties
284
     * @param array $options
285
     * @return void
286
     */
287
    private function prepareOptions(array $options): void
288
    {
289
        if (isset($options['sandbox'])) {
290
            $this->sandbox = (bool)$options['sandbox'];
291
        }
292
        if (isset($options['apiKey'])) {
293
            $this->apiKey = (string)$options['apiKey'];
294
        }
295
        if (isset($options['url'])) {
296
            $this->url = rtrim($options['url'], '/');
297
        }
298
        if (isset($options['sandboxUrl'])) {
299
            $this->sandboxUrl = rtrim($options['sandboxUrl'], '/');
300
        }
301
    }
302
303
    /**
304
     * Validate options
305
     * @param array $options
306
     * @return void
307
     * @throws InvalidApiKey if no API key given
308
     */
309
    private function validateOptions(array $options): void
310
    {
311
        if (empty($options['apiKey'])) {
312
            throw new Exception\InvalidApiKey('Access forbidden. Invalid API key.', 0);
313
        }
314
    }
315
316
    /**
317
     * Validate query parameters
318
     * @param QueryInterface $query
319
     * @return void
320
     */
321
    private function validate(QueryInterface $query): void
322
    {
323
        $violations = $this->validator->validate(
324
            $query->getFields(),
325
            $query->getValidationConstraints()
326
        );
327
328
        if (count($violations) !== 0) {
329
            throw new Exception\QueryValidator('Query parameters validation failed', $violations);
330
        }
331
    }
332
}
333