Passed
Push — master ( 2b97dd...4cf6b1 )
by Jonathan
20:51
created

AbstractReportingCloud   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 595
Duplicated Lines 0 %

Test Coverage

Coverage 97.8%

Importance

Changes 0
Metric Value
wmc 33
eloc 131
dl 0
loc 595
ccs 89
cts 91
cp 0.978
rs 9.76
c 0
b 0
f 0

21 Methods

Rating   Name   Duplication   Size   Complexity  
A setClient() 0 5 1
A setBaseUri() 0 5 1
A getDebug() 0 7 2
A request() 0 22 4
A getClient() 0 21 2
A getAuthorizationHeader() 0 18 4
A getTimeout() 0 7 2
A uri() 0 5 1
A setVersion() 0 5 1
A setDebug() 0 5 1
A setTest() 0 5 1
A getBaseUri() 0 7 2
A setApiKey() 0 5 1
A getUsername() 0 3 1
A getTest() 0 7 2
A setUsername() 0 5 1
A getApiKey() 0 3 1
A getPassword() 0 3 1
A setTimeout() 0 5 1
A setPassword() 0 5 1
A getVersion() 0 7 2
1
<?php
2
declare(strict_types=1);
3
4
/**
5
 * ReportingCloud PHP SDK
6
 *
7
 * PHP SDK for ReportingCloud Web API. Authored and supported by Text Control GmbH.
8
 *
9
 * @link      https://www.reporting.cloud to learn more about ReportingCloud
10
 * @link      https://github.com/TextControl/txtextcontrol-reportingcloud-php for the canonical source repository
11
 * @license   https://raw.githubusercontent.com/TextControl/txtextcontrol-reportingcloud-php/master/LICENSE.md
12
 * @copyright © 2019 Text Control GmbH
13
 */
14
15
namespace TxTextControl\ReportingCloud;
16
17
use GuzzleHttp\Client;
18
use GuzzleHttp\Exception\TransferException;
19
use GuzzleHttp\RequestOptions;
20
use Psr\Http\Message\ResponseInterface;
21
use TxTextControl\ReportingCloud\Exception\InvalidArgumentException;
22
use TxTextControl\ReportingCloud\Exception\RuntimeException;
23
use TxTextControl\ReportingCloud\Filter\Filter;
24
25
/**
26
 * Abstract ReportingCloud
27
 *
28
 * @package TxTextControl\ReportingCloud
29
 * @author  Jonathan Maron (@JonathanMaron)
30
 */
31
abstract class AbstractReportingCloud
32
{
33
    // <editor-fold desc="Constants (default values)">
34
35
    /**
36
     * Default date/time format of backend is 'ISO 8601'
37
     *
38
     * Note, last letter is 'P' and not 'O':
39
     *
40
     * O - Difference to Greenwich time (GMT) in hours (e.g. +0200)
41
     * P - Difference to Greenwich time (GMT) with colon between hours and minutes (e.g. +02:00)
42
     *
43
     * Backend uses the 'P' variant
44
     *
45
     * @const DEFAULT_DATE_FORMAT
46
     */
47
    public const DEFAULT_DATE_FORMAT = 'Y-m-d\TH:i:sP';
48
49
    /**
50
     * Default time zone of backend
51
     *
52
     * @const DEFAULT_TIME_ZONE
53
     */
54
    public const DEFAULT_TIME_ZONE = 'UTC';
55
56
    /**
57
     * Default base URI of backend
58
     *
59
     * @const DEFAULT_BASE_URI
60
     */
61
    protected const DEFAULT_BASE_URI = 'https://api.reporting.cloud';
62
63
    /**
64
     * Default version string of backend
65
     *
66
     * @const DEFAULT_VERSION
67
     */
68
    protected const DEFAULT_VERSION = 'v1';
69
70
    /**
71
     * Default timeout of backend in seconds
72
     *
73
     * @const DEFAULT_TIMEOUT
74
     */
75
    protected const DEFAULT_TIMEOUT = 120;
76
77
    /**
78
     * Default test flag of backend
79
     *
80
     * @const DEFAULT_TEST
81
     */
82
    protected const DEFAULT_TEST = false;
83
84
    /**
85
     * Default debug flag of REST client
86
     *
87
     * @const DEFAULT_DEBUG
88
     */
89
    protected const DEFAULT_DEBUG = false;
90
91
    // </editor-fold>
92
93
    // <editor-fold desc="Constants (document dividers)">
94
95
    /**
96
     * Document divider - none
97
     */
98
    public const DOCUMENT_DIVIDER_NONE = 1;
99
100
    /**
101
     * Document divider - new paragraph
102
     */
103
    public const DOCUMENT_DIVIDER_NEW_PARAGRAPH = 2;
104
105
    /**
106
     * Document divider - new section
107
     */
108
    public const DOCUMENT_DIVIDER_NEW_SECTION = 3;
109
110
    // </editor-fold>
111
112
    // <editor-fold desc="Constants (file formats)">
113
114
    /**
115
     * DOC file format
116
     */
117
    public const FILE_FORMAT_DOC = 'DOC';
118
119
    /**
120
     * DOCX file format
121
     */
122
    public const FILE_FORMAT_DOCX = 'DOCX';
123
124
    /**
125
     * HTML file format
126
     */
127
    public const FILE_FORMAT_HTML = 'HTML';
128
129
    /**
130
     * PDF file format
131
     */
132
    public const FILE_FORMAT_PDF = 'PDF';
133
134
    /**
135
     * PDF/A file format
136
     */
137
    public const FILE_FORMAT_PDFA = 'PDFA';
138
139
    /**
140
     * RTF file format
141
     */
142
    public const FILE_FORMAT_RTF = 'RTF';
143
144
    /**
145
     * TX (Text Control) file format
146
     */
147
    public const FILE_FORMAT_TX = 'TX';
148
149
    /**
150
     * Pure text file format
151
     */
152
    public const FILE_FORMAT_TXT = 'TXT';
153
154
    /**
155
     * Bitmap file format
156
     */
157
    public const FILE_FORMAT_BMP = 'BMP';
158
159
    /**
160
     * GIF file format
161
     */
162
    public const FILE_FORMAT_GIF = 'GIF';
163
164
    /**
165
     * JPEG file format
166
     */
167
    public const FILE_FORMAT_JPG = 'JPG';
168
169
    /**
170
     * PNG file format
171
     */
172
    public const FILE_FORMAT_PNG = 'PNG';
173
174
    // </editor-fold>
175
176
    // <editor-fold desc="Constants (file format collections)">
177
178
    /**
179
     * Image file formats
180
     */
181
    public const FILE_FORMATS_IMAGE
182
        = [
183
            self::FILE_FORMAT_BMP,
184
            self::FILE_FORMAT_GIF,
185
            self::FILE_FORMAT_JPG,
186
            self::FILE_FORMAT_PNG,
187
        ];
188
189
    /**
190
     * Template file formats
191
     */
192
    public const FILE_FORMATS_TEMPLATE
193
        = [
194
            self::FILE_FORMAT_DOC,
195
            self::FILE_FORMAT_DOCX,
196
            self::FILE_FORMAT_RTF,
197
            self::FILE_FORMAT_TX,
198
        ];
199
200
    /**
201
     * Document file formats
202
     */
203
    public const FILE_FORMATS_DOCUMENT
204
        = [
205
            self::FILE_FORMAT_DOC,
206
            self::FILE_FORMAT_DOCX,
207
            self::FILE_FORMAT_HTML,
208
            self::FILE_FORMAT_PDF,
209
            self::FILE_FORMAT_RTF,
210
            self::FILE_FORMAT_TX,
211
        ];
212
213
    /**
214
     * Return file formats
215
     */
216
    public const FILE_FORMATS_RETURN
217
        = [
218
            self::FILE_FORMAT_DOC,
219
            self::FILE_FORMAT_DOCX,
220
            self::FILE_FORMAT_HTML,
221
            self::FILE_FORMAT_PDF,
222
            self::FILE_FORMAT_PDFA,
223
            self::FILE_FORMAT_RTF,
224
            self::FILE_FORMAT_TX,
225
            self::FILE_FORMAT_TXT,
226
        ];
227
228
    // </editor-fold>
229
230
    // <editor-fold desc="Properties">
231
232
    /**
233
     * Backend API key
234
     *
235
     * @var string|null
236
     */
237
    private $apiKey;
238
239
    /**
240
     * Backend username
241
     *
242
     * @var string|null
243
     */
244
    private $username;
245
246
    /**
247
     * Backend password
248
     *
249
     * @var string|null
250
     */
251
    private $password;
252
253
    /**
254
     * When true, API call does not count against quota
255
     * "TEST MODE" watermark is added to document
256
     *
257
     * @var bool|null
258
     */
259
    private $test;
260
261
    /**
262
     * Backend base URI
263
     *
264
     * @var string|null
265
     */
266
    private $baseUri;
267
268
    /**
269
     * Backend version string
270
     *
271
     * @var string|null
272
     */
273
    private $version;
274
275
    /**
276
     * Backend timeout in seconds
277
     *
278
     * @var int|null
279
     */
280
    private $timeout;
281
282
    /**
283
     * Debug flag of REST client
284
     *
285
     * @var bool|null
286
     */
287
    private $debug;
288
289
    /**
290
     * REST client to backend
291
     *
292
     * @var Client|null
293
     */
294
    private $client;
295
296
    // </editor-fold>
297
298
    // <editor-fold desc="Methods">
299
300
    /**
301
     * Return the API key
302
     *
303
     * @return string|null
304
     */
305 94
    public function getApiKey(): ?string
306
    {
307 94
        return $this->apiKey;
308
    }
309
310
    /**
311
     * Set the API key
312
     *
313
     * @param string $apiKey
314
     *
315
     * @return AbstractReportingCloud
316
     */
317 211
    public function setApiKey(string $apiKey): self
318
    {
319 211
        $this->apiKey = $apiKey;
320
321 211
        return $this;
322
    }
323
324
    /**
325
     * Return the username
326
     *
327
     * @return string|null
328
     */
329 15
    public function getUsername(): ?string
330
    {
331 15
        return $this->username;
332
    }
333
334
    /**
335
     * Set the username
336
     *
337
     * @param string $username
338
     *
339
     * @return AbstractReportingCloud
340
     */
341 12
    public function setUsername(string $username): self
342
    {
343 12
        $this->username = $username;
344
345 12
        return $this;
346
    }
347
348
    /**
349
     * Return the password
350
     *
351
     * @return string|null
352
     */
353 15
    public function getPassword(): ?string
354
    {
355 15
        return $this->password;
356
    }
357
358
    /**
359
     * Set the password
360
     *
361
     * @param string $password
362
     *
363
     * @return AbstractReportingCloud
364
     */
365 12
    public function setPassword(string $password): self
366
    {
367 12
        $this->password = $password;
368
369 12
        return $this;
370
    }
371
372
    /**
373
     * Return the base URI of the backend web service
374
     *
375
     * @return string|null
376
     */
377 103
    public function getBaseUri(): ?string
378
    {
379 103
        if (null === $this->baseUri) {
380 97
            $this->setBaseUri(self::DEFAULT_BASE_URI);
381
        }
382
383 103
        return $this->baseUri;
384
    }
385
386
    /**
387
     * Set the base URI of the backend web service
388
     *
389
     * @param string $baseUri
390
     *
391
     * @return AbstractReportingCloud
392
     */
393 103
    public function setBaseUri(string $baseUri): self
394
    {
395 103
        $this->baseUri = $baseUri;
396
397 103
        return $this;
398
    }
399
400
    /**
401
     * Get the timeout (in seconds) of the backend web service
402
     *
403
     * @return int|null
404
     */
405 100
    public function getTimeout(): ?int
406
    {
407 100
        if (null === $this->timeout) {
408 94
            $this->setTimeout(self::DEFAULT_TIMEOUT);
409
        }
410
411 100
        return $this->timeout;
412
    }
413
414
    /**
415
     * Set the timeout (in seconds) of the backend web service
416
     *
417
     * @param int $timeout
418
     *
419
     * @return AbstractReportingCloud
420
     */
421 100
    public function setTimeout(int $timeout): self
422
    {
423 100
        $this->timeout = $timeout;
424
425 100
        return $this;
426
    }
427
428
    /**
429
     * Return the debug flag
430
     *
431
     * @return bool|null
432
     */
433 100
    public function getDebug(): ?bool
434
    {
435 100
        if (null === $this->debug) {
436 94
            $this->setDebug(self::DEFAULT_DEBUG);
437
        }
438
439 100
        return $this->debug;
440
    }
441
442
    /**
443
     * Set the debug flag
444
     *
445
     * @param bool $debug Debug flag
446
     *
447
     * @return AbstractReportingCloud
448
     */
449 100
    public function setDebug(bool $debug): self
450
    {
451 100
        $this->debug = $debug;
452
453 100
        return $this;
454
    }
455
456
    /**
457
     * Return the test flag
458
     *
459
     * @return bool|null
460
     */
461 91
    public function getTest(): ?bool
462
    {
463 91
        if (null === $this->test) {
464 85
            $this->setTest(self::DEFAULT_TEST);
465
        }
466
467 91
        return $this->test;
468
    }
469
470
    /**
471
     * Set the test flag
472
     *
473
     * @param bool $test
474
     *
475
     * @return AbstractReportingCloud
476
     */
477 91
    public function setTest(bool $test): self
478
    {
479 91
        $this->test = $test;
480
481 91
        return $this;
482
    }
483
484
    /**
485
     * Get the version string of the backend web service
486
     *
487
     * @return string|null
488
     */
489 97
    public function getVersion(): ?string
490
    {
491 97
        if (null === $this->version) {
492 91
            $this->version = self::DEFAULT_VERSION;
493
        }
494
495 97
        return $this->version;
496
    }
497
498
    /**
499
     * Set the version string of the backend web service
500
     *
501
     * @param string $version
502
     *
503
     * @return AbstractReportingCloud
504
     */
505 6
    public function setVersion(string $version): self
506
    {
507 6
        $this->version = $version;
508
509 6
        return $this;
510
    }
511
512
    /**
513
     * Return the REST client of the backend web service
514
     *
515
     * @return Client|null
516
     */
517 94
    public function getClient(): ?Client
518
    {
519 94
        if (!$this->client instanceof Client) {
520
521
            $headers = [
522 94
                'Authorization' => $this->getAuthorizationHeader()
523
            ];
524
525
            $options = [
526 91
                'base_uri'              => $this->getBaseUri(),
527 91
                RequestOptions::TIMEOUT => $this->getTimeout(),
528 91
                RequestOptions::DEBUG   => $this->getDebug(),
529 91
                RequestOptions::HEADERS => $headers,
530
            ];
531
532 91
            $client = new Client($options);
533
534 91
            $this->setClient($client);
535
        }
536
537 91
        return $this->client;
538
    }
539
540
    /**
541
     * Set the REST client of the backend web service
542
     *
543
     * @param Client $client
544
     *
545
     * @return AbstractReportingCloud
546
     */
547 91
    public function setClient(Client $client): self
548
    {
549 91
        $this->client = $client;
550
551 91
        return $this;
552
    }
553
554
    /**
555
     * Request the URI with options
556
     *
557
     * @param string $method  HTTP method
558
     * @param string $uri     URI
559
     * @param array  $options Options
560
     *
561
     * @return ResponseInterface
562
     * @throws RuntimeException
563
     */
564 88
    protected function request(string $method, string $uri, array $options): ResponseInterface
565
    {
566 88
        $client = $this->getClient();
567
568 85
        if (!$client instanceof Client) {
0 ignored issues
show
introduced by
$client is always a sub-type of GuzzleHttp\Client.
Loading history...
569
            $message = 'No HTTP Client has been set.';
570
            throw new RuntimeException($message);
571
        }
572
573
        try {
574 85
            $test = (bool) $this->getTest();
575 85
            if ($test) {
576 3
                $options[RequestOptions::QUERY]['test'] = Filter::filterBooleanToString($test);
577
            }
578 85
            $response = $client->request($method, $uri, $options);
579 6
        } catch (TransferException $e) {
580 6
            $message = (string) $e->getMessage();
581 6
            $code    = (int) $e->getCode();
582 6
            throw new RuntimeException($message, $code);
583
        }
584
585 82
        return $response;
586
    }
587
588
    /**
589
     * Construct URI with version number
590
     *
591
     * @param string $uri URI
592
     *
593
     * @return string
594
     */
595 88
    protected function uri(string $uri): string
596
    {
597 88
        $version = (string) $this->getVersion();
598
599 88
        return sprintf('/%s%s', $version, $uri);
600
    }
601
602
    /**
603
     * Return Authorization Header, with either API key or username and password
604
     *
605
     * @return string
606
     * @throws InvalidArgumentException
607
     */
608 94
    private function getAuthorizationHeader(): string
609
    {
610 94
        $apiKey = (string) $this->getApiKey();
611
612 94
        if (!empty($apiKey)) {
613 88
            return sprintf('ReportingCloud-APIKey %s', $apiKey);
614
        }
615
616 6
        $username = (string) $this->getUsername();
617 6
        $password = (string) $this->getPassword();
618
619 6
        if (!empty($username) && !empty($password)) {
620 3
            $value = sprintf('%s:%s', $username, $password);
621 3
            return sprintf('Basic %s', base64_encode($value));
622
        }
623
624 3
        $message = 'Either the API key, or username and password must be set for authorization';
625 3
        throw new InvalidArgumentException($message);
626
    }
627
628
    // </editor-fold>
629
}
630