Completed
Push — master ( 8f1019...13ce36 )
by Žilvinas
04:20 queued 01:35
created

Client::downloadFile()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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